Custos is a security middleware used to authenticate users to Airavata-based Science Gateways. It is relevant to the Science Gateways community to unify authentication and also authenticate users to JupyterHub using the same framework.

Custos is a hosted solution managed by Indiana University, therefore it has no maintenance burden and supports CILogon so that users can login with credentials from almost all US Higher Education Institutions.


I have been testing on Jetstream 2, however it should work easily on any Kubernetes deployment. If you also are testing on Jetstream 2, you can follow my previous tutorials to:

Configure Custos

First you can request a new tenant on the Custos hosted service, for testing you can use the development version at:

then, for production, switch to:

After having completed the process, you should see that your tenant is in the “Requested” state, wait for the Custos admins to approve it.

Configure JupyterHub

Custom authenticators for JupyterHub need to be installed in the Docker image used to run the hub pod. The Custos Authenticator for JupyterHub has a package on PyPI so it is easy to add it to the JupyterHub image. See this issue on zero-to-jupyterhub for more details

The Custos developers maintain Docker images which have this patch already applied, see the repository on DockerHub.

We can therefore modify the JupyterHub configuration (config_standard_storage.yaml in my tutorials) and add:

    name: apachecustos/jupyter-hub-k8
    tag: 1.2.0

Consider that this will need to be updated if we change the version of the Helm recipe (currently 1.2.0).

Configure the Custos Authenticator

Once the Custos tenant has been approved, we can proceed to configure JupyterHub with the right credentials, again, modify config_standard_storage.yaml to add:

      00-custos: |
        from custosauthenticator.custos import CustosOAuthenticator
        c.JupyterHub.authenticator_class = CustosOAuthenticator
        c.CustosOAuthenticator.oauth_callback_url = ""
        c.CustosOAuthenticator.client_id = "custos-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        c.CustosOAuthenticator.client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        c.CustosOAuthenticator.login_service = "Custos Login"
        c.CustosOAuthenticator.custos_host= ""

Finally you can test in your browser, you probably need to test with an account different than the one you used to setup the tenant, so for example if you used XSEDE, now use CILogon with your institution or use ORCID.

With this default configuration, any user that can login to Custos can also login to JupyterHub, so if you already have permissions setup for your Custos gateway, those will be also applied to JupyterHub.

Work in progress