Skip to content

Commit

Permalink
Add ID Token support
Browse files Browse the repository at this point in the history
  • Loading branch information
benjimin committed Jan 30, 2024
1 parent 5667bf1 commit 505fbd2
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 0 deletions.
26 changes: 26 additions & 0 deletions oauthenticator/oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""
import base64
import json
import jwt
import os
import uuid
from urllib.parse import quote, urlencode, urlparse, urlunparse
Expand Down Expand Up @@ -361,11 +362,16 @@ def _token_url_default(self):

userdata_url = Unicode(
config=True,
allow_none=True,
help="""
The URL to where this authenticator makes a request to acquire user
details with an access token received via a request to the
:attr:`token_url`.
If this is explicitly set to None, this authenticator will attempt
to instead use an id token if one was provided by the
:attr:`token_url`.
For more context, see the `Protocol Flow section
<https://www.rfc-editor.org/rfc/rfc6749#section-1.2>`_ in the OAuth2
standard document, specifically steps E-F.
Expand Down Expand Up @@ -863,6 +869,8 @@ async def token_to_user(self, token_info):
Determines who the logged-in user by sending a "GET" request to
:data:`oauthenticator.OAuthenticator.userdata_url` using the `access_token`.
If `userdata_url` is None, checks for an `id_token` instead.
Args:
token_info: the dictionary returned by the token request (exchanging the OAuth code for an Access Token)
Expand All @@ -871,6 +879,24 @@ async def token_to_user(self, token_info):
Called by the :meth:`oauthenticator.OAuthenticator.authenticate`
"""
self.log.info(f"TOKEN_TO_USER -- userdata_url={repr(self.userdata_url)}")
if self.userdata_url is None:
id_token = token_info.get("id_token", None)
if not id_token:
raise web.HTTPError(
500,
f"An id token was not returned: {token_info}\nPlease configure authenticator.userdata_url"
)
self.log.info(f"RAW ID TOKEN {id_token}")
# Here we parse and validate the id token. Note that per OIDC spec (core v1.0 sect. 3.1.3.7.6) we
# could skip signature validation because the hub has obtained the tokens from the id provider
# directly. Google also advises that token validation may be skipped assuming the provider is trusted.
# https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
# https://developers.google.com/identity/openid-connect/openid-connect#obtainuserinfo
result = jwt.decode(id_token, key=self.client_secret, audience=self.client_id)
self.log.info(f"ID TOKEN CONTENTS: {result}")
return result

access_token = token_info["access_token"]
token_type = token_info["token_type"]

Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ requests
ruamel.yaml
tornado
traitlets
# PyJWT is used for parsing id tokens
pyjwt

0 comments on commit 505fbd2

Please sign in to comment.