Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce refresh token clean-up #130

Merged
merged 5 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion egi_notebooks_hub/egiauthenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@


class JWTHandler(BaseHandler):
"""Handler for authentication with JWT tokens"""

async def exchange_for_refresh_token(self, access_token):
self.log.debug("Exchanging access token for refresh")
http_client = AsyncHTTPClient()
Expand Down Expand Up @@ -237,7 +239,7 @@ async def jwt_authenticate(self, handler, data=None):
username = self.user_info_to_username(user_info)
username = self.normalize_username(username)

# check if there any refresh_token in the token_info dict
# check if there is any refresh_token in the token_info dict
refresh_token = data.get("refresh_token", None)
if self.enable_auth_state and not refresh_token:
self.log.debug(
Expand Down Expand Up @@ -303,6 +305,17 @@ async def refresh_user(self, user, handler=None):
)
return True

try:
if jwt.decode(
access_token,
options=dict(verify_signature=False, verify_exp=True),
):
# access token is good, no need to keep going
self.log.debug("Access token is still good, no refresh needed")
return True
except jwt.exceptions.InvalidTokenError as e:
self.log.debug(f"Invalid access token, will try to refresh: {e}")

now = time.time()
refresh_info = auth_state.get("refresh_info", {})
# if the token is still valid, avoid refreshing
Expand Down Expand Up @@ -343,6 +356,10 @@ async def refresh_user(self, user, handler=None):
resp = await http_client.fetch(req)
except HTTPClientError as e:
self.log.warning("Unable to refresh token, maybe expired: %s", e)
if e.response:
self.log.warning("Response from server: %s", e.response.body)
# clear here the existing auth state so it's no longer valid
await user.save_auth_state(None)
return False
refresh_info = json.loads(resp.body.decode("utf8", "replace"))
refresh_info["expiry_time"] = now + refresh_info["expires_in"]
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
jupyterhub>=4.0.2
oauthenticator>=16.3.0
oauthenticator>=16.3.0,<17
jupyterhub-kubespawner>=6.1.0
xmltodict
fastapi
fastapi[standard]
pydantic-settings
pbr