[GenericOAuthenticator] Pulling `claim_groups_key` from another token than the one returned by `USERDATA_URL` for AWS Cognito

Hi there,
First off, thank you for the amazing work and product :pray: I am grateful that such a vibrant community is backing it up.

I’m using GenericOAuthenticator and AWS Cognito to manage authentication/authorization to Jupyterhub, but I’m facing the following issue:

I’ve searched on this forum and elsewhere, but alas I haven’t found any solution or discussion around this issue. Right now I’m using a custom class inheriting from GenericOAuthenticator and patching a method to get the group claim from the ACCESS token, but this does not feel great.

Is there a better way, and if not, is there an appetite and some design ideas for an improvement there?
I’m ready to implement some changes and open a PR for this if needed.

Hi! Could you provide a bit more information on your overall goals? Are you wanting to lookup a user’s groups and only allow login if they’re a member of that group? Are you wanting to somehow map the AWS Cognito group to a JupyterHub group? Or are you wanting to fetch that information and save it for later use?

For the first case one option could be to change the claim_groups_key so that the callable version takes both user_data_resp_json and token_resp_json (might make sense to do the same for username_key?):

1 Like

FYI We’re running with jupyterhub/ zero-to-jupyterhub-k8s v1.2, AFAIU it doesn’t have any impact on the issue at hand.

The goals of the setup we have working right now are the following:

  1. When a user logs in, get their cognito:groups claim using the claim_groups_key and only allow a certain set of groups using allowed_groups

  2. Keep track of the user auth state all the way to the options_form and present custom spawn options based on their groups.

  3. Keep track of the user auth state all the way to the KubeSpawner to validate that the form selection received is actually authorized.

The last two points are achieved thanks to enable_auth_state, JUPYTERHUB_CRYPT_KEY and a custom auth_state_hook (more or less following this part of the documentation)

The only real issue we have is the hackish way we fetch the claim in the access token (instead of the default userdata token) and then add it to the user_data_resp_json dictionary. From that point on, everything flows.

Might be important design-wise, reading the access token requires a jwt.decode, so some TLS verification ideally.