Hello,
Background
I’m running into an issue with my Jupyter Notebook when using the NullAuthenticator. I’m leveraging the JupyterHub API to start a server and generate a token for the user. I then navigate to the spawned server’s endpoint using the token http://localhost:8000/user/<username>/?token=<token>
. The notebook is visible and seems to work as expected, however attempting to execute a cell generates the error in the console shown below.
WebSocket connection to 'ws://localhost:8000/user/<username>/api/kernels/04218e9c-183c-471a-96ef-02cf3d770e9b/channels?session_id=8eccf31d-173c-496e-ae48-2565bd2a9f49' failed: Error during WebSocket handshake: Unexpected response code: 403
Checking the logs of the notebook instance (running in a container via DockerSpawner) I see that I get the corresponding error.
[W 2023-07-19 16:32:48.175 ServerApp] 403 GET /user/<username>/api/kernels/04218e9c-183c-471a-96ef-02cf3d770e9b/channels?session_id=8eccf31d-173c-496e-ae48-2565bd2a9f49 (@::ffff:172.21.0.1) 1.41m
If I change the autheticator from null
to dummy
and don’t provide the token in the URL, then I can run the cells, so I assume it is how I’m generating/configuring the token.
Question
What am I missing that is blocking the websocket from being established?
Supporting Content
JupyterHub Config
c = get_config()
## Network Settings
# we need the hub to listen on all ips when it is in a container
c.JupyterHub.hub_ip = '0.0.0.0'
# the hostname/ip that should be used to connect to the hub
# this is usually the hub container's name
c.JupyterHub.hub_connect_ip = 'jupyterhub'
## Authenticator Setting
# Use null authenticator so login is only possible through API
c.JupyterHub.authenticator_class = 'null'
## Spawner Settings
# Use custom spawner
c.JupyterHub.spawner_class = 'filespawner.FileSpawner'
# Network used to communicate with user containers
c.DockerSpawner.network_name = 'jupyterhub'
# Delete containers when they are stopped
c.DockerSpawner.remove = True
## API Settings
# Create the NIST service
c.JupyterHub.services = [
{ 'name': 'service-custom', 'api_token': '<my token>' }
]
# Grant NIST service account admin privledges
c.JupyterHub.load_roles = [
{
'name': 'service-role',
'scopes': [
# Ability to control users
'admin:users',
# Ability to start/stop/delete servers
'admin:servers',
# Ability to make tokens
'tokens',
# See current users
'list:users'
],
'services': [
# assign the service the above permissions
'service-custom'
],
}
]
Code Snippet for Token Generation
async function requestToken(user) {
const response = await fetch(`http://localhost:8000/hub/api/users/${user}/tokens`, {
method: 'POST',
headers: AUTH_HEADER
});
console.log(await response.text());
}