Base classes for Custom Authenticator to use OAuth with JupyterHub

Most of the code c/o Kyle Kelley (@rgbkrk)

class oauthenticator.oauth2.OAuthLoginHandler(application: Application, request: HTTPServerRequest, **kwargs: Any)#

Base class for OAuth login handler

Typically subclasses will need

class oauthenticator.oauth2.OAuthCallbackHandler(application: Application, request: HTTPServerRequest, **kwargs: Any)#

Basic handler for OAuth callback. Calls authenticator to verify username.

class oauthenticator.oauth2.OAuthenticator(**kwargs: Any)#

Base class for OAuthenticators

Subclasses must override:

login_service (string identifying the service provider) authenticate (method takes one arg - the request handler handling the oauth callback)

admin_users c.OAuthenticator.admin_users = Set()#

Set of users that will have admin rights on this JupyterHub.

Note: As of JupyterHub 2.0, full admin rights should not be required, and more precise permissions can be managed via roles.

Admin users have extra privileges:
  • Use the admin panel to see list of users logged in

  • Add / remove users in some authenticators

  • Restart / halt the hub

  • Start / stop users’ single-user servers

  • Can access each individual users’ single-user server (if configured)

Admin access should be treated the same way root access is.

Defaults to an empty set, in which case no user has admin access.

allowed_users c.OAuthenticator.allowed_users = Set()#

Set of usernames that are allowed to log in.

Use this with supported authenticators to restrict which users can log in. This is an additional list that further restricts users, beyond whatever restrictions the authenticator has in place. Any user in this list is granted the ‘user’ role on hub startup.

If empty, does not perform any additional restriction.

Changed in version 1.2: Authenticator.whitelist renamed to allowed_users

auth_refresh_age c.OAuthenticator.auth_refresh_age = Int(300)#

The max age (in seconds) of authentication info before forcing a refresh of user auth info.

Refreshing auth info allows, e.g. requesting/re-validating auth tokens.

See refresh_user() for what happens when user auth info is refreshed (nothing by default).

async authenticate(handler, data=None, **kwargs)#

Authenticate a user with login form data

This must be a coroutine.

It must return the username on successful authentication, and return None on failed authentication.

Checking allowed_users/blocked_users is handled separately by the caller.

Changed in version 0.8: Allow authenticate to return a dict containing auth_state.

  • handler (tornado.web.RequestHandler) – the current request handler

  • data (dict) – The formdata of the login form. The default form has ‘username’ and ‘password’ fields.


The username of the authenticated user, or None if Authentication failed.

The Authenticator may return a dict instead, which MUST have a key name holding the username, and MAY have additional keys:

  • auth_state, a dictionary of of auth state that will be persisted;

  • admin, the admin setting value for the user

  • groups, the list of group names the user should be a member of, if Authenticator.manage_groups is True.

Return type:

user (str or dict or None)

authorize_url c.OAuthenticator.authorize_url = Unicode('')#

The authenticate url for initiating oauth

auto_login c.OAuthenticator.auto_login = Bool(False)#

Automatically begin the login process

rather than starting with a “Login with…” link at /hub/login

To work, .login_url() must give a URL other than the default /hub/login, such as an oauth handler or another automatic login handler, registered with .get_handlers().

New in version 0.8.

auto_login_oauth2_authorize c.OAuthenticator.auto_login_oauth2_authorize = Bool(False)#

Automatically begin login process for OAuth2 authorization requests

When another application is using JupyterHub as OAuth2 provider, it sends users to /hub/api/oauth2/authorize. If the user isn’t logged in already, and auto_login is not set, the user will be dumped on the hub’s home page, without any context on what to do next.

Setting this to true will automatically redirect users to login if they aren’t logged in only on the /hub/api/oauth2/authorize endpoint.

New in version 1.5.

basic_auth c.OAuthenticator.basic_auth = Bool(True)#

Whether or not to use basic authentication for access token request

blocked_users c.OAuthenticator.blocked_users = Set()#

Set of usernames that are not allowed to log in.

Use this with supported authenticators to restrict which users can not log in. This is an additional block list that further restricts users, beyond whatever restrictions the authenticator has in place.

If empty, does not perform any additional restriction.

Changed in version 1.2: Authenticator.blacklist renamed to blocked_users

build_access_tokens_request_params(handler, data=None)#

Builds the parameters that should be passed to the URL request that exchanges the OAuth code for the Access Token. Called by the oauthenticator.OAuthenticator.authenticate().

build_auth_state_dict(token_info, user_info)#

Builds the auth_state dict that will be returned by a succesfull authenticate method call.

  • token_info – the dictionary returned by the token request (exchanging the OAuth code for an Access Token)

  • user_info – the dictionary returned by the userdata request


a dictionary of auth state that should be persisted with the following keys:
  • ”access_token”: the access_token

  • ”refresh_token”: the refresh_token, if available

  • ”id_token”: the id_token, if available

  • ”scope”: the scopes, if available

  • ”token_response”: the full token_info response

  • self.user_auth_state_key: the full user_info response

Return type:


Called by the oauthenticator.OAuthenticator.authenticate()


Builds and returns the headers to be used in the access token request. Called by the oauthenticator.OAuthenticator.get_token_info().

build_userdata_request_headers(access_token, token_type)#

Builds and returns the headers to be used in the userdata request. Called by the oauthenticator.OAuthenticator.token_to_user()


alias of OAuthCallbackHandler

client_id c.OAuthenticator.client_id = Unicode('')#

No help string is provided.

client_secret c.OAuthenticator.client_secret = Unicode('')#

No help string is provided.

custom_403_message c.OAuthenticator.custom_403_message = Unicode('Sorry, you are not currently authorized to use this hub. Please contact the hub administrator.')#

The message to be shown when user was not allowed

delete_invalid_users c.OAuthenticator.delete_invalid_users = Bool(False)#

Delete any users from the database that do not pass validation

When JupyterHub starts, .add_user will be called on each user in the database to verify that all users are still valid.

If delete_invalid_users is True, any users that do not pass validation will be deleted from the database. Use this if users might be deleted from an external system, such as local user accounts.

If False (default), invalid users remain in the Hub’s database and a warning will be issued. This is the default to avoid data loss due to config changes.

enable_auth_state c.OAuthenticator.enable_auth_state = Bool(False)#

Enable persisting auth_state (if available).

auth_state will be encrypted and stored in the Hub’s database. This can include things like authentication tokens, etc. to be passed to Spawners as environment variables.

Encrypting auth_state requires the cryptography package.

Additionally, the JUPYTERHUB_CRYPT_KEY environment variable must contain one (or more, separated by ;) 32B encryption keys. These can be either base64 or hex-encoded.

If encryption is unavailable, auth_state cannot be persisted.

New in JupyterHub 0.8

extra_authorize_params c.OAuthenticator.extra_authorize_params = Dict()#

Extra GET params to send along with the initial OAuth request to the OAuth provider.

async fetch(req, label='fetching', parse_json=True, **kwargs)#

Wrapper for http requests

logs error responses, parses successful JSON responses

  • req – tornado HTTPRequest

  • label (str) – label describing what is happening, used in log message when the request fails.

  • **kwargs – remaining keyword args passed to underlying client.fetch(req, **kwargs)


parsed JSON response

Return type:



Get my OAuth redirect URL

Either from config or guess based on the current request.


Return any custom handlers the authenticator needs to register

Used in conjugation with login_url and logout_url.


app (JupyterHub Application) – the application object, in case it needs to be accessed for info.


list of ('/url', Handler) tuples passed to tornado. The Hub prefix is added to any URLs.

Return type:

handlers (list)

async get_prev_refresh_token(handler, username)#

Retrieves the refresh_token from previous encrypted auth state. Called by the oauthenticator.OAuthenticator.authenticate()

async get_token_info(handler, params)#

Makes a “POST” request to self.token_url, with the parameters received as argument.


the JSON response to the token_url the request.

Called by the oauthenticator.OAuthenticator.authenticate()


alias of OAuthLoginHandler


Override this when registering a custom login handler

Generally used by authenticators that do not use simple form-based authentication.

The subclass overriding this is responsible for making sure there is a handler available to handle the URL returned from this method, using the get_handlers method.


base_url (str) – the base URL of the Hub (e.g. /hub/)


The login URL, e.g. ‘/hub/login’

Return type:



alias of OAuthLogoutHandler

logout_redirect_url c.OAuthenticator.logout_redirect_url = Unicode('')#

URL for logging out of Auth0


Override when registering a custom logout handler

The subclass overriding this is responsible for making sure there is a handler available to handle the URL returned from this method, using the get_handlers method.


base_url (str) – the base URL of the Hub (e.g. /hub/)


The logout URL, e.g. ‘/hub/logout’

Return type:


manage_groups c.OAuthenticator.manage_groups = Bool(False)#

Let authenticator manage user groups

If True, Authenticator.authenticate and/or .refresh_user may return a list of group names in the ‘groups’ field, which will be assigned to the user.

All group-assignment APIs are disabled if this is True.

oauth_callback_url c.OAuthenticator.oauth_callback_url = Unicode('')#

Callback URL to use. Typically https://{host}/hub/oauth_callback

post_auth_hook c.OAuthenticator.post_auth_hook = Any(None)#

An optional hook function that you can implement to do some bootstrapping work during authentication. For example, loading user account details from an external system.

This function is called after the user has passed all authentication checks and is ready to successfully authenticate. This function must return the authentication dict reguardless of changes to it.

This maybe a coroutine.


import os, pwd
def my_hook(authenticator, handler, authentication):
    user_data = pwd.getpwnam(authentication['name'])
    spawn_data = {
        'pw_data': user_data
        'gid_list': os.getgrouplist(authentication['name'], user_data.pw_gid)

    if authentication['auth_state'] is None:
        authentication['auth_state'] = {}
    authentication['auth_state']['spawn_data'] = spawn_data

    return authentication

c.Authenticator.post_auth_hook = my_hook
refresh_pre_spawn c.OAuthenticator.refresh_pre_spawn = Bool(False)#

Force refresh of auth prior to spawn.

This forces refresh_user() to be called prior to launching a server, to ensure that auth state is up-to-date.

This can be important when e.g. auth tokens that may have expired are passed to the spawner via environment variables from auth_state.

If refresh_user cannot refresh the user auth data, launch will fail until the user logs in again.

scope c.OAuthenticator.scope = List()#

The OAuth scopes to request. See the OAuth documentation of your OAuth provider for options. For GitHub in particular, you can see github_scopes.md in this repo.

token_params c.OAuthenticator.token_params = Dict()#

Extra parameters for first POST request exchanging the OAuth code for an Access Token

async token_to_user(token_info)#

Determines who the logged-in user by sending a “GET” request to oauthenticator.OAuthenticator.userdata_url using the access_token.


token_info – the dictionary returned by the token request (exchanging the OAuth code for an Access Token)


the JSON response to the userdata_url request.

Called by the oauthenticator.OAuthenticator.authenticate()

token_url c.OAuthenticator.token_url = Unicode('')#

The url retrieving an access token at the completion of oauth

async update_auth_model(auth_model, **kwargs)#

Updates auth_model dict if any fields have changed or additional information is available or returns the unchanged auth_model.

Returns the model unchanged by default.

Should be overridden to take into account changes like group/admin membership.

Args: auth_model - the auth model dictionary dict instead, containing:
  • the name key holding the username

  • the auth_state key, the dictionary of of auth state

    returned by oauthenticator.OAuthenticator.build_auth_state_dict()

Called by the oauthenticator.OAuthenticator.authenticate()

user_auth_state_key c.OAuthenticator.user_auth_state_key = Unicode('oauth_user')#

The name of the user key expected to be present in auth_state.


Gets the self.username_claim key’s value from the user_info dictionary. This is equivalent to the JupyterHub username.

Should be overridden by the authenticators for which the hub username cannot be extracted this way and needs extra processing.


user_info – the dictionary returned by the userdata request


user_info[“self.username_claim”] or raises an error if such value isn’t found.

Called by the oauthenticator.OAuthenticator.authenticate()

async user_is_authorized(auth_model)#

Checks if the user that is authenticating should be authorized or not and False otherwise. Should be overridden with any relevant logic specific to each oauthenticator.

Returns True by default.

Called by the oauthenticator.OAuthenticator.authenticate()

userdata_params c.OAuthenticator.userdata_params = Dict()#

Userdata params to get user data login information

userdata_token_method c.OAuthenticator.userdata_token_method = Unicode('header')#

Method for sending access token in userdata request. Supported methods: header, url. Default: header

userdata_url c.OAuthenticator.userdata_url = Unicode('')#

The url for retrieving user data with a completed access token

username_claim c.OAuthenticator.username_claim = Unicode('username')#

Field in userdata reply to use for username The field in the userdata response from which to get the JupyterHub username. Examples include: email, username, nickname

What keys are available will depend on the scopes requested and the authenticator used.

username_map c.OAuthenticator.username_map = Dict()#

Dictionary mapping authenticator usernames to JupyterHub users.

Primarily used to normalize OAuth user names to local users.

username_pattern c.OAuthenticator.username_pattern = Unicode('')#

Regular expression pattern that all valid usernames must match.

If a username does not match the pattern specified here, authentication will not be attempted.

If not set, allow any username.

validate_server_cert c.OAuthenticator.validate_server_cert = Bool(False)#

No help string is provided.

whitelist c.OAuthenticator.whitelist = Set()#

Deprecated, use Authenticator.allowed_users