diff --git a/CHANGES.rst b/CHANGES.rst
index cf9e38f..2a95b40 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -3,6 +3,10 @@ Changelog
 
 A list of changes between each release
 
+0.6.0.dev1 (unreleased)
+^^^^^^^^^^^^^^^^^^
+- Added auto-reauthorization (token refresh) when a request fails due to an expired token
+
 0.6.0.dev0 (unreleased)
 ^^^^^^^^^^^^^^^^^^
 - Removed redundent properties that only called hidden variables
diff --git a/blinkpy.py b/blinkpy.py
index 4ec5a75..cae947c 100644
--- a/blinkpy.py
+++ b/blinkpy.py
@@ -22,8 +22,15 @@ from helpers.constants import (BLINK_URL, LOGIN_URL,
                                DEFAULT_URL, ONLINE)
 
 
-def _request(url, data=None, headers=None, reqtype='get',
-             stream=False, json_resp=True):
+def _attempt_reauthorization(blink):
+    """Attempt to refresh auth token and links."""
+    headers = blink.get_auth_token()
+    blink.set_links()
+    return headers
+
+
+def _request(blink, url='http://google.com', data=None, headers=None,
+             reqtype='get', stream=False, json_resp=True, is_retry=False):
     """Wrapper function for request."""
     if reqtype == 'post':
         response = requests.post(url, headers=headers,
@@ -35,8 +42,14 @@ def _request(url, data=None, headers=None, reqtype='get',
         raise BlinkException(ERROR.REQUEST)
 
     if json_resp and 'code' in response.json():
-        raise BlinkAuthenticationException(
-            (response.json()['code'], response.json()['message']))
+        if is_retry:
+            raise BlinkAuthenticationException(
+                (response.json()['code'], response.json()['message']))
+        else:
+            headers = _attempt_reauthorization(blink)
+            return _request(blink, url=url, data=data, headers=headers,
+                            reqtype=reqtype, stream=stream,
+                            json_resp=json_resp, is_retry=True)
 
     if json_resp:
         return response.json()
@@ -75,9 +88,10 @@ class BlinkURLHandler(object):
 class BlinkCamera(object):
     """Class to initialize individual camera."""
 
-    def __init__(self, config, urls):
+    def __init__(self, config, blink):
         """Initiailize BlinkCamera."""
-        self.urls = urls
+        self.blink = blink
+        self.urls = self.blink.urls
         self.id = str(config['device_id'])  # pylint: disable=invalid-name
         self.name = config['name']
         self._status = config['armed']
@@ -99,15 +113,18 @@ class BlinkCamera(object):
 
     def snap_picture(self):
         """Take a picture with camera to create a new thumbnail."""
-        _request(self.image_link, headers=self.header, reqtype='post')
+        _request(self.blink, url=self.image_link,
+                 headers=self.header, reqtype='post')
 
     def set_motion_detect(self, enable):
         """Set motion detection."""
         url = self.arm_link
         if enable:
-            _request(url + 'enable', headers=self.header, reqtype='post')
+            _request(self.blink, url=url + 'enable',
+                     headers=self.header, reqtype='post')
         else:
-            _request(url + 'disable', headers=self.header, reqtype='post')
+            _request(self.blink, url=url + 'disable',
+                     headers=self.header, reqtype='post')
 
     def update(self, values):
         """Update camera information."""
@@ -122,7 +139,7 @@ class BlinkCamera(object):
     def image_refresh(self):
         """Refresh current thumbnail."""
         url = self.urls.home_url
-        response = _request(url, headers=self.header,
+        response = _request(self.blink, url=url, headers=self.header,
                             reqtype='get')['devices']
         for element in response:
             try:
@@ -137,7 +154,7 @@ class BlinkCamera(object):
     def image_to_file(self, path):
         """Write image to file."""
         thumb = self.image_refresh()
-        response = _request(thumb, headers=self.header,
+        response = _request(self.blink, url=thumb, headers=self.header,
                             reqtype='get', stream=True, json_resp=False)
         if response.status_code == 200:
             with open(path, 'wb') as imgfile:
@@ -183,7 +200,7 @@ class Blink(object):
         """Get all events on server."""
         url = self.urls.event_url + self.network_id
         headers = self._auth_header
-        self._events = _request(url, headers=headers,
+        self._events = _request(self, url=url, headers=headers,
                                 reqtype='get')['event']
         return self._events
 
@@ -192,7 +209,7 @@ class Blink(object):
         """Return boolean system online status."""
         url = self.urls.network_url + self.network_id + '/syncmodules'
         headers = self._auth_header
-        return ONLINE[_request(url, headers=headers,
+        return ONLINE[_request(self, url=url, headers=headers,
                                reqtype='get')['syncmodule']['status']]
 
     def last_motion(self):
@@ -224,7 +241,7 @@ class Blink(object):
         else:
             value_to_append = 'disarm'
         url = self.urls.network_url + self.network_id + '/' + value_to_append
-        _request(url, headers=self._auth_header, reqtype='post')
+        _request(self, url=url, headers=self._auth_header, reqtype='post')
 
     def refresh(self):
         """Get all blink cameras and pulls their most recent status."""
@@ -248,7 +265,7 @@ class Blink(object):
         if self._auth_header is None:
             raise BlinkException(ERROR.AUTH_TOKEN)
 
-        return _request(url, headers=headers, reqtype='get')
+        return _request(self, url=url, headers=headers, reqtype='get')
 
     def get_cameras(self):
         """Find and creates cameras."""
@@ -258,7 +275,7 @@ class Blink(object):
                     element['device_type'] == 'camera'):
                 # Add region to config
                 element['region_id'] = self.region_id
-                device = BlinkCamera(element, self.urls)
+                device = BlinkCamera(element, self)
                 self.cameras[device.name] = device
                 self._idlookup[device.id] = device.name
 
@@ -306,13 +323,13 @@ class Blink(object):
             "password": self._password,
             "client_specifier": "iPhone 9.2 | 2.2 | 222"
         })
-        response = _request(LOGIN_URL, headers=headers,
+        response = _request(self, url=LOGIN_URL, headers=headers,
                             data=data, json_resp=False, reqtype='post')
         if response.status_code is 200:
             response = response.json()
             (self.region_id, self.region), = response['region'].items()
         else:
-            response = _request(LOGIN_BACKUP_URL, headers=headers,
+            response = _request(self, url=LOGIN_BACKUP_URL, headers=headers,
                                 data=data, reqtype='post')
             self.region_id = 'rest.piri'
             self.region = "UNKNOWN"
@@ -325,6 +342,8 @@ class Blink(object):
 
         self.urls = BlinkURLHandler(self.region_id)
 
+        return self._auth_header
+
     def get_ids(self):
         """Set the network ID and Account ID."""
         url = self.urls.networks_url
@@ -333,6 +352,6 @@ class Blink(object):
         if self._auth_header is None:
             raise BlinkException(ERROR.AUTH_TOKEN)
 
-        response = _request(url, headers=headers, reqtype='get')
+        response = _request(self, url=url, headers=headers, reqtype='get')
         self.network_id = str(response['networks'][0]['id'])
         self.account_id = str(response['networks'][0]['account_id'])
diff --git a/helpers/constants.py b/helpers/constants.py
index b323e12..193d50b 100644
--- a/helpers/constants.py
+++ b/helpers/constants.py
@@ -6,7 +6,7 @@ import os
 
 MAJOR_VERSION = 0
 MINOR_VERSION = 6
-PATCH_VERSION = '0.dev0'
+PATCH_VERSION = '0.dev1'
 
 __version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
 

Token Checking/Reauthorization
Token expires after 24hrs. Would like to add in a feature where the token are handled behind the scenes in order to be backwards compatible with existing module that rely on blinkpy (such as the home assistant Blink module).

Perhaps when blinkpy calls the _request function we do a token check and grab a new one if the existing token has expired?
diff --git a/tests/test_blink_functions.py b/tests/test_blink_functions.py
index a4685e5..cb2ba8b 100644
--- a/tests/test_blink_functions.py
+++ b/tests/test_blink_functions.py
@@ -18,6 +18,7 @@ class TestBlinkFunctions(unittest.TestCase):
                                    password=PASSWORD)
         (self.region_id, self.region), = mresp.LOGIN_RESPONSE['region'].items()
         self.test_urls = blinkpy.BlinkURLHandler(self.region_id)
+        self.urls = self.test_urls
 
     def tearDown(self):
         """Clean up after test."""
@@ -25,6 +26,7 @@ class TestBlinkFunctions(unittest.TestCase):
         self.region = None
         self.region_id = None
         self.test_urls = None
+        self.urls = None
 
     @mock.patch('blinkpy.blinkpy.requests.post',
                 side_effect=mresp.mocked_requests_post)
@@ -122,7 +124,8 @@ class TestBlinkFunctions(unittest.TestCase):
         """Checks that the update function is doing the right thing."""
         self.test_urls = blinkpy.BlinkURLHandler('test')
         test_config = mresp.FIRST_CAMERA
-        test_camera = blinkpy.blinkpy.BlinkCamera(test_config, self.test_urls)
+        self.urls = self.test_urls
+        test_camera = blinkpy.blinkpy.BlinkCamera(test_config, self)
         test_update = mresp.SECOND_CAMERA
         test_camera.update(test_update)
         test_image_url = self.test_urls.base_url + test_update['thumbnail']
diff --git a/tests/test_blink_system.py b/tests/test_blink_system.py
index a67f362..cde365a 100644
--- a/tests/test_blink_system.py
+++ b/tests/test_blink_system.py
@@ -47,7 +47,7 @@ class TestBlinkSetup(unittest.TestCase):
             self.blink_no_cred.get_auth_token()
 
     def test_no_auth_header(self):
-        """Check that we throw an excpetion when no auth header given."""
+        """Check that we throw an exception when no auth header given."""
         # pylint: disable=unused-variable
         (region_id, region), = mresp.LOGIN_RESPONSE['region'].items()
         self.blink.urls = blinkpy.BlinkURLHandler(region_id)
@@ -79,7 +79,7 @@ class TestBlinkSetup(unittest.TestCase):
 
         with self.assertRaises(blinkpy.BlinkAuthenticationException):
             # pylint: disable=protected-access
-            blinkpy.blinkpy._request(None, reqtype='post')
+            blinkpy.blinkpy._request(None, reqtype='post', is_retry=True)
 
     @mock.patch('blinkpy.blinkpy.requests.post',
                 side_effect=mresp.mocked_requests_post)

pip install -e .
parse_log_pytest
requirements.txt
tox pytest pytest-cov pytest-timeout
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
-e git+https://github.com/fronzbot/blinkpy.git@b0cb3dda37ba51cf268112f7732ed38bd21fd9eb#egg=blinkpy
certifi==2021.5.30
charset-normalizer==2.0.12
coverage==6.2
distlib==0.3.9
filelock==3.4.1
fixtures==4.0.1
idna==3.10
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
packaging==21.3
pbr==6.1.1
platformdirs==2.4.0
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
pytest-cov==4.0.0
pytest-timeout==2.1.0
requests==2.27.1
six==1.17.0
testtools==2.6.0
toml==0.10.2
tomli==1.2.3
tox==3.28.0
typing_extensions==4.1.1
urllib3==1.26.20
virtualenv==20.17.1
zipp==3.6.0

name: blinkpy
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - charset-normalizer==2.0.12
      - coverage==6.2
      - distlib==0.3.9
      - filelock==3.4.1
      - fixtures==4.0.1
      - idna==3.10
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - packaging==21.3
      - pbr==6.1.1
      - platformdirs==2.4.0
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - pytest-timeout==2.1.0
      - requests==2.27.1
      - six==1.17.0
      - testtools==2.6.0
      - toml==0.10.2
      - tomli==1.2.3
      - tox==3.28.0
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - virtualenv==20.17.1
      - zipp==3.6.0
prefix: /opt/conda/envs/blinkpy

tests/test_blink_functions.py::TestBlinkFunctions::test_camera_update tests/test_blink_system.py::TestBlinkSetup::test_bad_request
tests/test_blink_functions.py::TestBlinkFunctions::test_camera_thumbs tests/test_blink_functions.py::TestBlinkFunctions::test_image_to_file tests/test_blink_functions.py::TestBlinkFunctions::test_image_with_bad_data tests/test_blink_functions.py::TestBlinkFunctions::test_last_motion tests/test_blink_functions.py::TestBlinkFunctions::test_set_motion_detect tests/test_blink_functions.py::TestBlinkFunctions::test_take_new_picture tests/test_blink_system.py::TestBlinkSetup::test_arm_disarm_system tests/test_blink_system.py::TestBlinkSetup::test_check_online_status tests/test_blink_system.py::TestBlinkSetup::test_full_setup tests/test_blink_system.py::TestBlinkSetup::test_initialization tests/test_blink_system.py::TestBlinkSetup::test_manual_login tests/test_blink_system.py::TestBlinkSetup::test_no_auth_header tests/test_blink_system.py::TestBlinkSetup::test_no_credentials tests/test_blink_system.py::TestBlinkSetup::test_setup_backup_subdomain tests/test_blink_system.py::TestBlinkSetup::test_system_bad_refresh
blinkpy.py helpers/constants.py CHANGES.rst
blinkpy.py helpers/constants.py CHANGES.rst