From b686d94f56ac9e8c8bbe19795e936ece4176cebf Mon Sep 17 00:00:00 2001 From: Bart Moorman Date: Sat, 1 Mar 2025 23:32:19 -0700 Subject: [PATCH 1/2] Refresh tokens before they expire --- twitchio/authentication/tokens.py | 49 ++++++++++++++++++------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/twitchio/authentication/tokens.py b/twitchio/authentication/tokens.py index 62466ea1..855ad8ba 100644 --- a/twitchio/authentication/tokens.py +++ b/twitchio/authentication/tokens.py @@ -229,6 +229,25 @@ def request_paginated( ) return iterator + async def _refresh_token(self, user_id: str, refresh: str) -> None: + try: + resp: RefreshTokenPayload = await self.__isolated.refresh_token(refresh) + except HTTPException as e: + if e.status >= 500: + raise + + self._tokens.pop(user_id, None) + logger.warning('Token for "%s" was invalid and could not be refreshed.', user_id) + else: + logger.debug('Token for "%s" was successfully refreshed.', user_id) + + self._tokens[user_id] = { + "user_id": user_id, + "token": resp.access_token, + "refresh": resp.refresh_token, + "last_validated": datetime.datetime.now().isoformat(), + } + async def _revalidate_all(self) -> None: logger.debug("Attempting to revalidate all tokens that have passed the timeout on %s.", self.__class__.__qualname__) @@ -238,31 +257,21 @@ async def _revalidate_all(self) -> None: continue try: - await self.__isolated.validate_token(data["token"]) + valid_resp: ValidateTokenPayload = await self.__isolated.validate_token(data["token"]) except HTTPException as e: if e.status >= 500: raise logger.debug('Token for "%s" was invalid or expired. Attempting to refresh token.', data["user_id"]) - - try: - refresh: RefreshTokenPayload = await self.__isolated.refresh_token(data["refresh"]) - except HTTPException as e: - if e.status >= 500: - raise - - self._tokens.pop(data["user_id"], None) - logger.warning('Token for "%s" was invalid and could not be refreshed.', data["user_id"]) - continue - - logger.debug('Token for "%s" was successfully refreshed.', data["user_id"]) - - self._tokens[data["user_id"]] = { - "user_id": data["user_id"], - "token": refresh.access_token, - "refresh": refresh.refresh_token, - "last_validated": datetime.datetime.now().isoformat(), - } + await self._refresh_token(data["user_id"], data["refresh"]) + else: + if valid_resp["expires_in"] <= 60: + logger.debug( + 'Token for "%s" expires in %s seconds. Attempting to refresh token.', + data["user_id"], + valid_resp["expires_in"], + ) + await self._refresh_token(data["user_id"], data["refresh"]) async def __validate_loop(self) -> None: logger.debug("Started the token validation loop on %s.", self.__class__.__qualname__) From a20997661f4f4619aeb792dbacbad99d8002f01e Mon Sep 17 00:00:00 2001 From: Bart Moorman Date: Sun, 2 Mar 2025 15:55:02 -0700 Subject: [PATCH 2/2] Assign dict values to variables --- twitchio/authentication/tokens.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/twitchio/authentication/tokens.py b/twitchio/authentication/tokens.py index 855ad8ba..6cfec6f6 100644 --- a/twitchio/authentication/tokens.py +++ b/twitchio/authentication/tokens.py @@ -252,26 +252,28 @@ async def _revalidate_all(self) -> None: logger.debug("Attempting to revalidate all tokens that have passed the timeout on %s.", self.__class__.__qualname__) for data in self._tokens.copy().values(): + user_id: str = data["user_id"] + token: str = data["token"] + refresh: str = data["refresh"] last_validated: datetime.datetime = datetime.datetime.fromisoformat(data["last_validated"]) + if last_validated + datetime.timedelta(minutes=60) > datetime.datetime.now(): continue try: - valid_resp: ValidateTokenPayload = await self.__isolated.validate_token(data["token"]) + valid_resp: ValidateTokenPayload = await self.__isolated.validate_token(token) except HTTPException as e: if e.status >= 500: raise - logger.debug('Token for "%s" was invalid or expired. Attempting to refresh token.', data["user_id"]) - await self._refresh_token(data["user_id"], data["refresh"]) + logger.debug('Token for "%s" was invalid or expired. Attempting to refresh token.', user_id) + await self._refresh_token(user_id, refresh) else: - if valid_resp["expires_in"] <= 60: - logger.debug( - 'Token for "%s" expires in %s seconds. Attempting to refresh token.', - data["user_id"], - valid_resp["expires_in"], - ) - await self._refresh_token(data["user_id"], data["refresh"]) + expires_in: int = valid_resp["expires_in"] + + if expires_in <= 60: + logger.debug('Token for "%s" expires in %s seconds. Attempting to refresh token.', user_id, expires_in) + await self._refresh_token(user_id, refresh) async def __validate_loop(self) -> None: logger.debug("Started the token validation loop on %s.", self.__class__.__qualname__)