diff --git a/CHANGELOG.md b/CHANGELOG.md
index 31c91c4db36b604ccedf899ba93d757ae630ffc2..6fbf09062d9d659e52022d139379a8138fda4857 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,13 +1,22 @@
 # Changelog
 ## [Latest](https://github.com/int-brain-lab/ONE/commits/main) [1.8.0]
 
+### Added
+
+- added `from_df` method to one.alf.io.AlfBunch
+- added `__version__` variable
+- added check for remote cache minimum API version
+- user prompted to verify settings correct in setup
+
 ### Modified
 
 - datasets cache table expected to have index of (eid, id).  NB: This changes the order of datasets returned by some functions
 - multithreading moved from One._download_datasets to one.webclient.http_download_file_list
 - cache_dir kwarg renamed to target_dir in one.webclient.http_download_file
 - 'table' attribute now split into columns and merged
-- added `from_df` method to one.alf.io.AlfBunch
+- when no username or password provided to constructor, AlyxClient init doesn't call authenticate
+- 'stay_logged_in' kwarg removed from AlyxClient constructor; must manually call `authenticate` or remember to call `logout`
+- user prompted whether to make url default in setup even if default already set
 
 ## [1.7.1]
 
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 2b1ad4ced5cc0be2339747c845277ad00368f6de..268607765556bd1615a0f231405630aca2d6379a 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -56,3 +56,34 @@ called.  To avoid this, run the following command instead:
 from one.api import OneAlyx
 new_one = OneAlyx.setup(base_url='https://alyx.example.com')
 ```
+
+## How do I change my download (a.k.a. cache) directory?
+For one-time changes, simply re-run the setup routine:
+```python
+from one.api import ONE
+new_one = ONE().setup()  # Re-run setup for default database
+```
+When prompted ('Enter the location of the download cache') enter the absolute path of the new download location.
+
+## How do check who I'm logged in as?
+```python
+from one.api import ONE
+one = ONE()
+if not one.offline:
+    print(one.alyx.user)
+    print(one.alyx.base_url)
+```
+
+## How do I log out, or temporarily log in as someone else?
+To log out:
+```python
+from one.api import ONE
+one = ONE()
+
+one.alyx.logout()
+```
+
+To log in as someone else temporarily:
+```python
+one.alyx.authenticate(username='other_user', cache_token=False, force=True)
+```
diff --git a/one/__init__.py b/one/__init__.py
index 21b29cefa23ec6032ae96203f36ff2b65b0fe488..b4939177112ef32fe70b66f534b6c178c73dd29d 100644
--- a/one/__init__.py
+++ b/one/__init__.py
@@ -1 +1,2 @@
 """The Open Neurophysiology Environment (ONE) API"""
+__version__ = '1.8.0'
diff --git a/one/api.py b/one/api.py
index 41550fae86365e270a5193707b719e375bd69ebc..2bd900fd400016fdf11eb30a2c29a92438f4b55e 100644
--- a/one/api.py
+++ b/one/api.py
@@ -2,7 +2,6 @@
 
 Things left to complete:
 
-    - TODO Add sig to ONE Light uuids.
     - TODO Save changes to cache.
     - TODO Fix update cache in AlyxONE - save parquet table.
     - TODO save parquet in update_filesystem.
@@ -10,6 +9,7 @@ Things left to complete:
 import collections.abc
 import warnings
 import logging
+import packaging.version
 from datetime import datetime, timedelta
 from functools import lru_cache, partial
 from inspect import unwrap
@@ -1235,6 +1235,14 @@ class OneAlyx(One):
         try:
             # Determine whether a newer cache is available
             cache_info = self.alyx.get('cache/info', expires=True)
+
+            # Check version compatibility
+            min_version = packaging.version.parse(cache_info.get('min_api_version', '0.0.0'))
+            if packaging.version.parse(one.__version__) < min_version:
+                warnings.warn(f'Newer cache tables require ONE version {min_version} or greater')
+                return
+
+            # Check whether remote cache more recent
             remote_created = datetime.fromisoformat(cache_info['date_created'])
             local_created = cache_meta.get('created_time', None)
             if local_created and (remote_created - local_created) < timedelta(minutes=1):
diff --git a/one/params.py b/one/params.py
index 1cb00c03df08727181f634ed40a7faa1a5ede70d..4661b274e2482fbe53c63f17dfad4232569bb87f 100644
--- a/one/params.py
+++ b/one/params.py
@@ -161,9 +161,15 @@ def setup(client=None, silent=False, make_default=None):
                 break
             cache_dir = input(prompt) or cache_dir  # Prompt for another directory
 
-        if make_default is None and 'DEFAULT' not in cache_map.as_dict():
+        if make_default is None:
             answer = input('Would you like to set this URL as the default one? [Y/n]')
-            make_default = True if not answer or answer[0].lower() == 'y' else False
+            make_default = (answer or 'y')[0].lower() == 'y'
+
+        # Verify setup pars
+        answer = input('Are the above settings correct? [Y/n]')
+        if answer and answer.lower()[0] == 'n':
+            print('SETUP ABANDONED.  Please re-run.')
+            return par_current
     else:
         par = par_current
 
diff --git a/one/tests/test_one.py b/one/tests/test_one.py
index b4e1f3114e875f7224ddbbc32e1ec0d75b489608..858ada952c0b83553c0eac89c862d612c5394046 100644
--- a/one/tests/test_one.py
+++ b/one/tests/test_one.py
@@ -936,6 +936,13 @@ class TestOneAlyx(unittest.TestCase):
                     self.one._load_cache(clobber=True)
                     self.assertEqual('local', self.one.mode)
                 self.assertTrue('Failed to connect' in lg.output[-1])
+
+            cache_info = {'min_api_version': '200.0.0'}
+            # Check version verification
+            with mock.patch.object(self.one.alyx, 'get', return_value=cache_info),\
+                    self.assertWarns(UserWarning):
+                self.one._load_cache(clobber=True)
+
         finally:  # Restore properties
             self.one.mode = 'auto'
             self.one.alyx.silent = True
diff --git a/one/tests/test_params.py b/one/tests/test_params.py
index 0bcf1b0ada2ca16f9de6005cbeca0fc2409a3682..b6b168aa8f6516bf00b3fd39d8958da8158fc968 100644
--- a/one/tests/test_params.py
+++ b/one/tests/test_params.py
@@ -26,13 +26,16 @@ class TestParamSetup(unittest.TestCase):
         self.get_file_mock.start()
         self.addCleanup(self.get_file_mock.stop)
 
-    def _mock_input(self, prompt):
+    def _mock_input(self, prompt, **kwargs):
         """Stub function for builtins.input"""
         if prompt.lower().startswith('warning'):
             return 'n'
         elif 'url' in prompt.lower():
             return self.url
         else:
+            for k, v in kwargs.items():
+                if k in prompt:
+                    return v
             return ''
 
     @mock.patch('one.params.getpass', return_value='mock_pwd')
@@ -51,6 +54,12 @@ class TestParamSetup(unittest.TestCase):
         self.assertEqual('https://' + self.url, par.ALYX_URL)
         self.assertEqual('mock_pwd', par.HTTP_DATA_SERVER_PWD)
 
+        # Check verification prompt
+        resp_map = {'ALYX_LOGIN': 'mistake', 'settings correct?': 'N'}
+        with mock.patch('one.params.input', new=partial(self._mock_input, **resp_map)):
+            cache = one.params.setup()
+            self.assertNotEqual(cache.ALYX_LOGIN, 'mistake')
+
         # Check that raises ValueError when bad URL provided
         self.url = 'ftp://'
         with self.assertRaises(ValueError), mock.patch('one.params.input', new=self._mock_input):
diff --git a/one/webclient.py b/one/webclient.py
index 84db03367f0b579fd4cdc6743378095920faef08..800761c2e78b8bcbe82a4228d5fc4e2825e3c9fc 100644
--- a/one/webclient.py
+++ b/one/webclient.py
@@ -471,7 +471,7 @@ class AlyxClient():
     base_url = None
 
     def __init__(self, base_url=None, username=None, password=None,
-                 cache_dir=None, silent=False, cache_rest='GET', stay_logged_in=True):
+                 cache_dir=None, silent=False, cache_rest='GET'):
         """
         Create a client instance that allows to GET and POST to the Alyx server.
         For One, constructor attempts to authenticate with credentials in params.py.
@@ -498,10 +498,11 @@ class AlyxClient():
         self._par = one.params.get(client=base_url, silent=self.silent)
         self.base_url = base_url or self._par.ALYX_URL
         self._par = self._par.set('CACHE_DIR', cache_dir or self._par.CACHE_DIR)
-        self.authenticate(username, password, cache_token=stay_logged_in)
+        if username or password:
+            self.authenticate(username, password)
         self._rest_schemes = None
         # the mixed accept application may cause errors sometimes, only necessary for the docs
-        self._headers['Accept'] = 'application/json'
+        self._headers = {**(self._headers or {}), 'Accept': 'application/json'}
         # REST cache parameters
         # The default length of time that cache file is valid for,
         # The default expiry is overridden by the `expires` kwarg.  If False, the caching is
diff --git a/requirements.txt b/requirements.txt
index d39688db45e85029b6886435e49fa142f6f3fdaa..070babb2c35e3c0ef118a1e6e305d93876875232 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,3 +4,4 @@ pandas>=1.2.4
 tqdm>=4.32.1
 requests>=2.22.0
 iblutil
+packaging
diff --git a/setup.py b/setup.py
index 2626b285d412c107d8347bf60f4a424c0f1fa006..3750d929fcc76c277398ba11284201746ca11d34 100644
--- a/setup.py
+++ b/setup.py
@@ -22,9 +22,20 @@ with open('README.md', 'r') as f:
 with open('requirements.txt') as f:
     require = [x.strip() for x in f.readlines() if not x.startswith('git+')]
 
+
+def get_version(rel_path):
+    here = Path(__file__).parent.absolute()
+    with open(here.joinpath(rel_path), 'r') as fp:
+        for line in fp.read().splitlines():
+            if line.startswith('__version__'):
+                delim = '"' if '"' in line else "'"
+                return line.split(delim)[1]
+    raise RuntimeError('Unable to find version string.')
+
+
 setup(
     name='ONE-api',
-    version='1.8.0',
+    version=get_version(Path('one', '__init__.py')),
     python_requires='>={}.{}'.format(*REQUIRED_PYTHON),
     description='Open Neurophysiology Environment',
     license="MIT",