Skip to content
Draft
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
13 changes: 3 additions & 10 deletions oauthenticator/azuread.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import os

import jwt
from jupyterhub.auth import LocalAuthenticator
from traitlets import Unicode, default

Expand Down Expand Up @@ -66,15 +65,9 @@ def _authorize_url_default(self):
def _token_url_default(self):
return f"https://login.microsoftonline.com/{self.tenant_id}/oauth2/token"

async def token_to_user(self, token_info):
id_token = token_info['id_token']
decoded = jwt.decode(
id_token,
options={"verify_signature": False},
audience=self.client_id,
)

return decoded
@default("userdata_from_id_token")
def _userdata_from_id_token_default(self):
return True


class LocalAzureAdOAuthenticator(LocalAuthenticator, AzureAdOAuthenticator):
Expand Down
20 changes: 17 additions & 3 deletions oauthenticator/oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ def _refresh_pre_spawn_default(self):

- True (no change)
- False (require new login)
- auth_model (dict - the new auth model, if anything should be changeed)
- auth_model (dict - the new auth model, if anything should be changed)
- None (proceed with default refresh_user behavior -
allows overriding refresh_user behavior for _some_ users)

Expand Down Expand Up @@ -1141,12 +1141,21 @@ async def token_to_user(self, token_info):
id_token,
audience=self.client_id,
options=dict(
verify_signature=False, verify_aud=True, verify_exp=True
# setting verify_signature to False makes all other
# verification default to False, making us need to
# opt-in to what we want to check
verify_signature=False,
verify_aud=True,
verify_exp=True,
),
)
except jwt.InvalidAudienceError:
raise
except jwt.ExpiredSignatureError:
raise
except Exception as err:
raise web.HTTPError(
500, f"Unable to decode id token: {id_token}\n{err}"
500, f"Unknown error decoding id token: {id_token}\n{err}"
)

access_token = token_info["access_token"]
Expand Down Expand Up @@ -1381,6 +1390,10 @@ async def refresh_user(self, user, handler=None, **kwargs):
auth_model = None
try:
auth_model = await self._token_to_auth_model(token_info)
except jwt.ExpiredSignatureError:
self.log.info(
f"id_token expired for {user.name}. Will try to refresh, if possible."
)
except HTTPClientError as e:
# assume any client error means an expired token
# most likely 401 or 403 for well-behaved providers
Expand All @@ -1390,6 +1403,7 @@ async def refresh_user(self, user, handler=None, **kwargs):
)
else:
raise

refresh_token = auth_state.get("refresh_token", None)
if refresh_token and not auth_model:
self.log.info(f"Refreshing oauth access token for {user.name}")
Expand Down