Hey everyone,
I’m looking for a way to painlessly allow users from another service to spawn and access a named server. Ideally, a user already authenticated with my service could just click a link to access their notebook and are authenticated behind the scenes via some sort of token. The topic How to access single user notebook in a web browser in API only mode? is the closest I could find to what I want to achieve. However, following those steps (in a local docker/non-kubernetes setup) I’ve only managed to receive 403 pages so far.
My Hub runs in a docker container in the docker network my-network
. Containers also spawn in this network. my-service
runs in another container in the same network. I communicate successfully with the Hub’s REST API using a predefined service and API token.
After starting the hub and service I do the following:
- Create new user
me
viaPOST HUB_URL/hub/api/users/me
- Can confirm user creation via
GET HUB_URL/hub/api/users
- Can confirm user creation via
- Create new named server
named
viaPOST HUB_URL/hub/api/users/me/servers/named
- Can confirm server created and running via
GET HUB_URL/hub/api/users
anddocker ps
- Can confirm server created and running via
- Create new API token for
me/named
viaPOST HUB_URL/hub/api/users/me/tokens
- Scopes:
access:servers!server=me/named
read:users:activity!user=me
users:activity!user=me
read:users:name!user=me
read:users:groups!user=me
- Scopes:
- Use the token as mentioned in the link above in the browser:
HUB_URL/user/me/named/?token={user_api_token}
I always receive 403 Forbidden.
What happens in the browser is that I am redirected several times:
302 GET HUB_URL/user/me/named/?token=<token_from_step_4>
302 GET HUB_URL/user/me/named/lab?token=<token_from_step_4>
302 GET HUB_URL/hub/api/oauth2/authorize?client_id=jupyterhub-user-me-named&redirect_uri=%2Fuser%2Fme%2Fnamed%2Foauth_callback&response_type=code&state=<some_value>
403 GET HUB_URL/hub/login?next=%2Fhub%2Fapi%2Foauth2%2Fauthorize%3Fclient_id%3Djupyterhub-user-me-named%26redirect_uri%3D%252Fuser%252Fme%252Fnamed%252Foauth_callback%26response_type%3Dcode%26state%3D<some_value>
What happens in the logs is:
2025-04-17 12:13:18 [I 2025-04-17 10:13:18.538 JupyterHub log:192] 302 GET /user/me/named/?token=[secret] -> /hub/user/me/named/?token=[secret] (@::ffff:192.168.65.1) 0.47ms
2025-04-17 12:13:18 [I 2025-04-17 10:13:18.545 JupyterHub log:192] 302 GET /hub/user/me/named/?token=[secret] -> /hub/login?next=%2Fhub%2Fuser%2Fme%2Fnamed%2F%3Ftoken%3D<token_from_step_4> (@::ffff:192.168.65.1) 0.44ms
2025-04-17 12:13:18 [W 2025-04-17 10:13:18.551 JupyterHub base:979] Failed login for unknown user
2025-04-17 12:13:18 [D 2025-04-17 10:13:18.551 JupyterHub base:1542] Using default error template for 403
2025-04-17 12:13:18 [W 2025-04-17 10:13:18.570 JupyterHub log:192] 403 GET /hub/login?next=%2Fhub%2Fuser%2Fme%2Fnamed%2F%3Ftoken%3D<token_from_step_4> (@::ffff:192.168.65.1) 19.54ms
Since the Hub/Authenticator apparently does not know about the user’s existence I’ve tried variations of the config (below) with c.Authenticator.allow_all = True
as suggested in the logs. However, the problem remains the same. I also tried the user server variant instead of the named servers, but also to no avail.
jupyterhub_config.py
c = get_config()
c.Application.log_level = 10
c.JupyterHub.allow_named_servers = True
c.JupyterHub.hub_ip = "docker-hub-hostname"
c.JupyterHub.hub_port = 8080
c.JupyterHub.load_roles = [
{
"name": "my-service-role",
"scopes": [
"admin:users",
"admin:servers",
"tokens",
"shares"
],
"services": ["my-service"]
}
]
c.JupyterHub.services = [
{
"name": "my-service",
"api_token": "some_api_token"
}
]
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
c.Spawner.mem_limit = '8G'
c.DockerSpawner.network_name = 'my-network'
c.DockerSpawner.use_internal_ip = True
c.DockerSpawner.debug = False
c.JupyterHub.authenticator_class = "null"
# c.hub_routespec = '/hub/api/'
(c.hub_routespec
deactivated for the moment to make sure that all routes are accessible)
JuypterHub Version Info from the logs
2025-04-17 11:58:35 [I 2025-04-17 09:58:35.412 JupyterHub app:3354] Running JupyterHub version 5.3.0
2025-04-17 11:58:35 [I 2025-04-17 09:58:35.412 JupyterHub app:3384] Using Authenticator: jupyterhub.auth.NullAuthenticator-5.3.0
2025-04-17 11:58:35 [I 2025-04-17 09:58:35.412 JupyterHub app:3384] Using Spawner: dockerspawner.dockerspawner.DockerSpawner-14.0.0
2025-04-17 11:58:35 [I 2025-04-17 09:58:35.412 JupyterHub app:3384] Using Proxy: jupyterhub.proxy.ConfigurableHTTPProxy-5.3.0
Limitations:
- I do not know the names of the users before they register to my service.
- I don’t want to create tokens in my service.
Unfortunately, I seem to be at my wit’s (and Google-fu’s) end. Probably I am fundamentally misunderstanding something and actually need to implement a custom authenticator instead of using the Null-Authenticator. However, if that is the case I also have no clue how to approach that for my case. Any advice is greatly appreciated!