Using JupyterHub as an identity provider#

JupyterHub can be used as an OAuth2 based identity provider for a community managed service of some kind. As an example, a community could themselves host a Discourse forum somewhere and login via the community’s JupyterHub (that in turn may ask users to login by another identity provider).

To help a community use JupyterHub as an identity provider, register an OAuth2 application with JupyterHub. This is done by declaring an externally managed JupyterHub service and configuring at least oauth_client_id and oauth_redirect_uri.

1. Request required information#

We need to configure [oauth_redirect_uri], and that is only the community managing the service using JupyterHub as an identity provider.

2. Configure JupyterHub#

  1. Define the service in the appropriate hub’s <hub-name>.values.yaml file:

    jupyterhub:
      hub:
        services:
          # name the service to make sense for an URL like
          # https://<community>.2i2c.cloud/services/<name>
          <name-of-service>:
            # The client_id for this service - it *must* start with service-
            oauth_client_id: service-<name-of-service>
            # The OAuth2 redirect URI provided to us by the community, such as
            # https://forum.community.org/auth/oauth2_basic/callback
            oauth_redirect_uri: <oauth-redirect-uri>
            # oauth_no_confirm is set to true to avoid a 'do you want to approve
            # this external service?' authorization prompt. Since this service is
            # only granted permission to read basic information about the user
            # and trusted by the community, it shouldn't be relevant
            oauth_no_confirm: true
        config:
          Authenticator:
            # This prevents the hub home page from showing when the end user
            # tries to authenticate with the hub from the external service.
            # Since the hub might send the user to CILogon or GitHub or another
            # auth service, removing this step makes the flow smoother.
            auto_login_oauth2_authorize: true
    
  2. Configure a client_secret

    The JupyterHub service’s api_token is used as a client_secret, lets configure it explicitly.

    First generate an appropriate OAuth2 client secret on the commandline by running openssl rand -hex 32, then define appropriate secrets in the hub’s enc-<hub-name>.secret.values.yaml file:

    jupyterhub:
      hub:
        services:
          <name-of-service>:
            # This will be the client secret
            api_token: <output-from-openssl>
    

    Note

    api_token gets generated by the JupyterHub chart if not explicitly set and could be read from a k8s Secret, but we choose to set it explicitly. With explicit configuration we can re-installing the chart in a new namespace or cluster without needing to ask the community to update the externally managed OAuth2 client with a re-generated api_token (client_secret).

  3. Commit and deploy.

3. Respond with setup information#

We now have enough information for the community to configure their OAuth2 client to authenticate against their JupyterHub!

Respond using a message template like below in a private channel:

An OAuth2 application has been registered with JupyterHub to make it usable
as an identity provider.

To configure a service to use JupyterHub as an identity provider, the
following information is relevant.

```
client_id: <oauth_client_id_from_step_1>
client_secret: <api_key_from_step_3>
authorization_url: https://<hub-domain>/hub/api/oauth2/authorize
token_url: https://<hub-domain>/hub/api/oauth2/token
userinfo_url: https://<hub-domain>/hub/api/user
```

Note that the `userinfo_url` should be accessed with an authorization HTTP
header like `Authorization: Bearer <access token>`. The JSON response will
include the JupyterHub username under the `name` key. For more details see
https://jupyterhub.readthedocs.io/en/stable/reference/rest-api.html#/default/get_user.