oauthenticator icon indicating copy to clipboard operation
oauthenticator copied to clipboard

Github - auth_state_groups_key cannot find teams dict keys

Open linkeal opened this issue 6 months ago • 2 comments

Bug description

When configuring Jupyterhub on Kubernetes via helm and configuring the GithubOAuthenticator to populate the teams and then also utilize those teams as group it cannot find the properties. Error message:

E 2025-06-09 19:13:22.282 JupyterHub oauth2:1245] The auth_state_groups_key teams does not exist in the auth_model. Available keys are: dict_keys(['access_token', 'refresh_token', 'id_token', 'scope', 'token_response', 'github_user', 'teams'])

How to reproduce

Config

helm upgrade --cleanup-on-fail
--install jupyterhub jupyterhub/jupyterhub
--namespace jupyterhub
--create-namespace
--version=4.2.0
--values values.yaml

hub:
  config:
    JupyterHub:
      authenticator_class: github
    GitHubOAuthenticator:
      client_id: "XXXX"
      client_secret: "XXXX"
      oauth_callback_url: "XXXX"
      manage_groups: true
      admin_groups:
        - jupyterhub-admins
      populate_teams_in_auth_state: true
      auth_state_groups_key: teams
      allowed_organizations:
        - XXXXX
      scope:
        - read:org
        - user:email

Expected behaviour

The Teams of the Organization from Github are validated in JupyterHub and if a User is part of the group (e.g. jupyterhub-admins) those users are granted admin permissions in JupyterHub.

Actual behaviour

Users can login since authentication is configured correctly, however every user is just a normal user. No admin permissions are granted to any user.

Your personal set up

  • OS: Kubernetes v1.30.3
  • Image: quay.io/jupyterhub/k8s-hub:4.2.0
  • Version(s):

jupyterhub==5.3.0 oauthenticator==17.3.0

Full environment
# paste output of `pip freeze` or `conda list` here
Configuration
# jupyterhub_config.py
Logs

linkeal avatar Jun 09 '25 19:06 linkeal

The error message may be misleading, since the set() call may also return a TypeError even if the key exists: https://github.com/jupyterhub/oauthenticator/blob/6d08bf21445888193adee225d9749c1098af91ae/oauthenticator/oauth2.py#L1240-L1248 Can you add some debugging to show the values of the teams field?

manics avatar Jun 09 '25 21:06 manics

Can you add some debugging to show the values of the teams field?

Hello Sorry for hijacking the thread, I have a similar issue. I have a 'groups' claim inside my id_token, so I'm trying to set auth_state_groups_key to id_token.groups. It fails with the similar The auth_state_groups_key id_token.groups does not exist in the auth_model. Available keys are: dict_keys(['access_token', 'refresh_token', 'id_token', 'scope', 'token_response', 'oauth_user']). Looking at the code, it seems that the call to reduce() is the culprit. I wonder if my auth_state is not what I expect it to be? Coming back to your comment, what is a way to debug this? How do I make the code print the auth_state? I'm also using JupyterHub through the Helm chart and I've tried setting debug.enabled to true but that still does not give me enough info.

Edit: Well I guess I should've looked more into this. id_token is saved as a string in auth_state, so no way to get a claim out of it. I had to change my auth_state_groups_key to oauth_user.groups. That did the trick for me! cheers!

cobotrifork avatar Jun 12 '25 16:06 cobotrifork

Thanks for your hint @cobotrifork ! I was trying to get the groups from Keycloak and the documentation was not very clear, but using oauth_user.<TOKEN CLAIM> worked for me, too!

belfhi avatar Jul 14 '25 08:07 belfhi

@belfhi or @cobotrifork: Can you maybe give me an example of the full config? We have in the meanwhile switched to Keycloak and would like to use client roles for the authorization. Authentication works, but the parsing of the groups for the authorization fails I guess: This is the config:


hub:
  config:
    GenericOAuthenticator:
      client_id: jupyterhub
      client_secret: XXXXX
      oauth_callback_url: https://jupyterhub.XXXXX.eu/hub/oauth_callback
      authorize_url: https://auth.XXXXXX.eu/realms/XXXX/protocol/openid-connect/auth
      token_url: https://auth.XXXXXX.eu/realms/XXXXX/protocol/openid-connect/token
      userdata_url: https://auth.XXXXX.eu/realms/XXXX/protocol/openid-connect/userinfo
      login_service: keycloak
      username_key: preferred_username
      auth_state_groups_key: oauth_user.resource_access.jupyterhub.roles
      scope:
        - openid
        - profile
        - email
        - roles
      manage_groups: true
      allowed_groups:
        - jupyterhub-admin
        - jupyterhub-contributor
      admin_groups:
        - jupyterhub-admin
    JupyterHub:
      authenticator_class: generic-oauth

I also with a seperate OpenID Connect debugger looked at JWT Access Tokens / ID Tokens. In the Access Token the client roles are exactly listed under the above listed: oauth_user.resource_access.jupyterhub.roles

Any ideas?

linkeal avatar Aug 01 '25 08:08 linkeal

@linkeal where are the roles defined in your access token? If I remember correctly, if you use auth_state_groups_key: oauth_user.resource_access.jupyterhub.roles, then I would expect the roles to be in resource_access.jupyterhub.roles of your access token. Is that the case?

cobotrifork avatar Aug 01 '25 08:08 cobotrifork

Yeah exactly @cobotrifork. The decoded access token contains the resource_access attribute like this:

{
.....
Normal access token attributes
.....
"resource_access": {
    "jupyterhub": {
      "roles": [
        "jupyterhub-admin"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
.....

linkeal avatar Aug 01 '25 10:08 linkeal

I think the groups are fetched from the userinfo endpoint. Are the Roles also present in the userinfo?

belfhi avatar Aug 01 '25 10:08 belfhi

Indeed @belfhi. Thanks for that hint! I got it working finally. My configuration for Jupyterhub in the helm chart above was perfectly fine. However the roles were not shared in the userinfo.

Enabling that in Keycloak under Client Scopes--> roles --> Mappers tab, select client roles and setting userinfo to on. That did the trick! On that journey the openid-connect debugger here helped me to actually see that the roles were missing in the userinfo: https://github.com/rcbj/oauth2-oidc-debugger

linkeal avatar Aug 01 '25 14:08 linkeal