Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document user grabbing self auth_state #3588

Closed
kafonek opened this issue Aug 27, 2021 · 10 comments
Closed

Document user grabbing self auth_state #3588

kafonek opened this issue Aug 27, 2021 · 10 comments

Comments

@kafonek
Copy link
Contributor

kafonek commented Aug 27, 2021

According to #3189, users should be able to access their own auth_state now that RBAC has landed in Jupyterhub 🎉 . Reading auth_state to get external oauth tokens (e.g. Keycloak access token) is a frequently asked question, and the usual workaround is for the spawner to push that information into the single user instance as an environment variable.

I am happy to add a section to https://jupyterhub.readthedocs.io/en/rbac/rbac/use-cases.html if I can figure out how to make auth_state available to users on my hub.

What I've tried

Running Jupyterhub 1.4.2 in Kubernetes with Keycloak authentication (GenericOAuthenticator). auth_state is enabled and the spawner sets an environment variable for the tokens, that is all good. When I GET <hub-host>/hub/api/user with header Authorization: token <jupyterhub_singleuser_api_token>, I get back user info (name, servers, etc) but no auth state.

Do I need to configure c.Jupyterhub.load_roles or load_groups in some manner to allow users to see their own auth state? Or is there an extra url parameter to /api/user to specify scope? Something else I'm missing?

Thank you.

@FoodyFood
Copy link

Also trying to figure it out, I read quite a few of the questions and issues and also read this page over here;

https://github.com/jupyterhub/jupyterhub/blob/main/docs/source/reference/authenticators.md

But his bit here confused me, where do I export this.

'''export JUPYTERHUB_CRYPT_KEY=$(openssl rand -hex 32)'''

Some background, I'm using the helm chart to deploy JupyterLab, and Keycloak as the auth providor.

When I deploy this, I could have that ENV variable set via a dockerfile when I build an image of the hub, or in kubernetes in some manner.

But would love more info around what happens then when i do a helm upgrade of the chart version, if this number changes per-image that I build of the hub itself. Will that break everything, or will it simply render any tokens already in the database dead/discarded.

@Cerebus
Copy link

Cerebus commented Feb 18, 2022

If anyone's hitting this issue looking for docs, this works:

  • enable_auth_state in your authenticator config.
  • Overwrite the user role with scopes ["self", "admin:auth_state!user"]
  • Overwrite the server role with scopes ["access:servers!user", "read:users:activity!user", "users:activity!user", "admin:auth_state!user"]

This lets the user see his own auth state, then grants the same to JUPYTERHUB_API_TOKEN, which has the server role assigned. Both are required because the server's grants can't exceed the user's grants.

Access the user's auth state from the /hub/api/users/{user} endpoint, this will return the user model with auth_state included. The ../user endpoint does not.

You could also set the server role scope to inherit (default 1.x behavior) but that would violate least-privilege.

@zzkristy
Copy link

zzkristy commented Jun 8, 2022

If anyone's hitting this issue looking for docs, this works:

  • enable_auth_state in your authenticator config.
  • Overwrite the user role with scopes ["self", "admin:auth_state!user"]
  • Overwrite the server role with scopes ["access:servers!user", "read:users:activity!user", "users:activity!user", "admin:auth_state!user"]

This lets the user see his own auth state, then grants the same to JUPYTERHUB_API_TOKEN, which has the server role assigned. Both are required because the server's grants can't exceed the user's grants.

Access the user's auth state from the /hub/api/users/{user} endpoint, this will return the user model with auth_state included. The ../user endpoint does not.

You could also set the server role scope to inherit (default 1.x behavior) but that would violate least-privilege.

it works!
thanks!

@kafonek kafonek closed this as completed Jun 8, 2022
@rajeshmarni
Copy link

If anyone's hitting this issue looking for docs, this works:

  • enable_auth_state in your authenticator config.
  • Overwrite the user role with scopes ["self", "admin:auth_state!user"]
  • Overwrite the server role with scopes ["access:servers!user", "read:users:activity!user", "users:activity!user", "admin:auth_state!user"]

This lets the user see his own auth state, then grants the same to JUPYTERHUB_API_TOKEN, which has the server role assigned. Both are required because the server's grants can't exceed the user's grants.

Access the user's auth state from the /hub/api/users/{user} endpoint, this will return the user model with auth_state included. The ../user endpoint does not.

You could also set the server role scope to inherit (default 1.x behavior) but that would violate least-privilege.

c.JupyterHub.load_roles = [
    {
        "name": "user",
        "description": "User Role for accessing auth_state via API",
        "scopes": ["self", "admin:auth_state!user"],
        "services": [],
    }, {
        "name": "server",
        "description": "Allows parties to start and stop user servers",
        "scopes": ["access:servers!user", "read:users:activity!user", "users:activity!user", "admin:auth_state!user"],
        "services":[]
    }
]

Made above changes in jupyterhub_config.py file and restarted the jupyterhub and auth_state is returned in API response.

Thanks.

@jack4it
Copy link

jack4it commented Apr 26, 2024

just had a success as well!

however, I had to generate a new token. the old ones that were from before the role change don't work

@jack4it
Copy link

jack4it commented Apr 27, 2024

my bad. ofc the reason is the default token $JUPYTERHUB_API_TOKEN is server role not the token role created via the UX

@minrk
Copy link
Member

minrk commented May 13, 2024

As stated in the error message:

403 GET /hub/api/users?state=ready (::1): Action is not authorized with current scopes; requires any of [list:users]

listing users requires the list:users scope. The above scopes only grant access to read your own state via /hub/api/user.

If you want this for all users, you need the scopes:

- "list:users" # GET /users endpoint
- "read:users" # read user models for all users
- "admin:users:auth_state" # read auth state for all users

@jack4it
Copy link

jack4it commented May 13, 2024

for people running into this relevant issue

[W 2024-05-12 07:21:04.226 JupyterHub web:1873] 403 GET /hub/api/users?state=ready (::1): Action is not authorized with current scopes; requires any of [list:users]
[W 2024-05-12 07:21:04.227 JupyterHub log:192] 403 GET /hub/api/users?state=[secret] (jupyterhub-idle-culler@::1) 3.49ms
[E 240512 07:21:04 ioloop:770] Exception in callback functools.partial(<bound method IOLoop._discard_future_result of <tornado.platform.asyncio.AsyncIOMainLoop object at 0x7f4610861e50>>, <Task finished name='Task-1' coro=<cull_idle() done, defined at /usr/local/lib/python3.11/site-packages/jupyterhub_idle_culler/__init__.py:78> exception=HTTP 403: Forbidden>)
    Traceback (most recent call last):
      File "/usr/local/lib/python3.11/site-packages/tornado/ioloop.py", line 750, in _run_callback
        ret = callback()
              ^^^^^^^^^^
      File "/usr/local/lib/python3.11/site-packages/tornado/ioloop.py", line 774, in _discard_future_result
        future.result()
      File "/usr/local/lib/python3.11/site-packages/jupyterhub_idle_culler/__init__.py", line 426, in cull_idle
        async for user in fetch_paginated(req):
      File "/usr/local/lib/python3.11/site-packages/jupyterhub_idle_culler/__init__.py", line 140, in fetch_paginated
        response = await resp_future
                   ^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/site-packages/jupyterhub_idle_culler/__init__.py", line 122, in fetch
        return await client.fetch(req)
               ^^^^^^^^^^^^^^^^^^^^^^^
    tornado.httpclient.HTTPClientError: HTTP 403: Forbidden

try to extend instead

      c.JupyterHub.load_roles.extend([
          {
              "name": "user",
              "description": "User Role for accessing auth_state via API",
              "scopes": ["self", "admin:auth_state!user"],
              "services": [],
          }, {
              "name": "server",
              "description": "Allows parties to start and stop user servers",
              "scopes": ["inherit"],
              "services":[]
          }
      ])

@hevara247
Copy link

Is the auth_token retrieved from /hub/api/users/{user} supposed to refresh over time?

I am encountering an issue where I keep retrieving expired tokens after about 30 minutes.

@minrk
Copy link
Member

minrk commented Nov 8, 2024

If your Authenticator implements refresh_user, accessing /hub/api/users/{user} will call refresh_user if the auth state is stale and the result will be present in the response. The default OAuthenticator does not implement refresh_user, but will soon: jupyterhub/oauthenticator#579 . With that PR, accessing /hub/api/users/{user} retrieves an up-to-date token, refreshing if necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants