Skip to main content

Jupyterhub oauth extension

Project description


This Authenticator is built on top of OAuthenticator, and authenticates users using OIDC and retrieves external Identity Provider (IDP) tokens using token exchange. This implementation is compatible with Keycloak as an Identity Broker and Google as an external IDP (see Internal Token to External Token Exchange).

It also implements a refresh mechanism, ensuring that both the internal access token as well as any external IDP tokens are updated individually. If the update is not possible, it forces a re-authentication of the user.

Sequence diagram

The OIDC + token exchange flow may be illustrated like in the following sequence diagram:

OIDC with token exchange


pip install tokenexchangeauthenticator


In your JupyterHub config file, set the authenticator and configure it:

# Enable the authenticator
c.JupyterHub.authenticator_class = 'tokenexchangeauthenticator.TokenExchangeAuthenticator'
c.TokenExchangeAuthenticator.username_key = 'preferred_username'
c.TokenExchangeAuthenticator.userdata_params = {'state': 'state', 'kc_idp_hint': 'google'}
c.TokenExchangeAuthenticator.logout_redirect_uri = ''
c.TokenExchangeAuthenticator.oauth_callback_url = ''

# Specify the issuer url, to get all the endpoints automatically from .well-known/openid-configuration
c.TokenExchangeAuthenticator.oidc_issuer = ''

# If you need to set a different scope, like adding the offline option for longer lived refresh token
c.TokenExchangeAuthenticator.scope = ['openid', 'email', 'offline_access']
# Request access tokens for other services by passing their id's (this uses the token exchange mechanism)
c.TokenExchangeAuthenticator.exchange_tokens = ['google']

Note on Google's authorization server

Google's authorization server only provideds the refresh_token in the response to the initial login request. Hence, the Identity Broker (e.g. Keycloak) will only get the refresh token on the first login so that subsequent token refresh may stop working (see issue on stack overflow). This can be remedied by prompting for re-consent at every login like this:

# This will force the retrieval of a refresh_token on every login
c.TokenExchangeAuthenticator.extra_authorize_params = {'prompt': 'consent'}

It's also necessary to configure the client ID and secret. This may be set directly like this:

# This will force the retrieval of a refresh_token on every login
c.TokenExchangeAuthenticator.client_id = 'client-id'
c.TokenExchangeAuthenticator.client_secret = 'secret'

Or by setting the following environment variables:


Expose the user's tokens

The user's tokens are stored using Jupyterhub's authentication state. These can optionally be exposed at a custom path which will only be accessible inside the user's single-user notebook. The path can be customised by setting:

# If set, exposes the user's access token(s) at this relative path
c.TokenExchangeAuthenticator.local_user_exposed_path = '/my-custom-path/userinfo'

Running tests

To run the tests locally:

$ pip install --upgrade --pre -r test-requirements.txt
$ pytest -v ./tokenexchangeauthenticator/tests/

Or you run a specific test file with:

$ pytest -v ./tokenexchangeauthenticator/tests/<test-file-name>

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for TokenExchangeAuthenticator, version 0.0.3
Filename, size File type Python version Upload date Hashes
Filename, size TokenExchangeAuthenticator-0.0.3.tar.gz (12.5 kB) File type Source Python version None Upload date Hashes View
Filename, size TokenExchangeAuthenticator-0.0.3-py2-none-any.whl (15.1 kB) File type Wheel Python version py2 Upload date Hashes View

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Huawei Huawei PSF Sponsor Microsoft Microsoft PSF Sponsor NVIDIA NVIDIA PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page