# Is JUPYTERHUB\_API\_TOKEN actually needed?

**URL:** <https://discourse.jupyter.org/t/is-jupyterhub-api-token-actually-needed/35626>\
**Category:** JupyterHub\
**Created:** [May 27, 2025, 8:16am UTC](https://discourse.jupyter.org/t/is-jupyterhub-api-token-actually-needed/35626 "2025-05-27T08:16:42Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![paolo](https://avatars.discourse-cdn.com/v4/letter/p/6f9a4e/32.png) [@paolo](https://discourse.jupyter.org/u/paolo)\
**Post date:** [May 27, 2025, 8:16am UTC](https://discourse.jupyter.org/t/is-jupyterhub-api-token-actually-needed/35626/1 "2025-05-27T08:16:42Z")

</div>

In the documentation I read the following:

> The spawner starts the server using `jupyterhub-singleuser` with some  
> environment variables like `JUPYTERHUB_API_TOKEN` and  
> `JUPYTERHUB_BASE_URL` which tell the single-user server how to connect  
> back to the hub in order to say that it’s ready.

I tried unsetting a bunch of env vars:

```auto
c.KubeSpawner.environment = {
    'JUPYTERHUB_API_TOKEN': '',
    'JPY_API_TOKEN': '',
    'KUBERNETES_SERVICE_PORT_HTTPS': '',
    'KUBERNETES_SERVICE_PORT': '',
    'KUBERNETES_PORT_443_TCP': '',
    'KUBERNETES_PORT_443_TCP_PROTO': '',
    'KUBERNETES_PORT_443_TCP_ADDR': '',
    'KUBERNETES_PORT_443_TCP_PORT': '',
    'KUBERNETES_SERVICE_HOST': '',
    'KUBERNETES_PORT': ''
}

```

and running `env` from inside the pod I can confirm that `JUPYTERHUB_API_TOKEN` and `JPY_API_TOKEN` are unset. However the single user pod is launched and runs successfully. How come?

---

<div class="post-metadata">

**Author:** ![manics](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/manics/32/85_2.png) [@manics](https://discourse.jupyter.org/u/manics)\
**Post date:** [May 29, 2025, 2:11pm UTC](https://discourse.jupyter.org/t/is-jupyterhub-api-token-actually-needed/35626/2 "2025-05-29T14:11:53Z")

</div>

`JUPYTERHUB_API_TOKEN` is required for the singleuser server to communicate with the hub. I’ve just tested this and as expected the singleuser server fails:

```auto
[E 2025-05-29 14:08:39.191 JupyterHubSingleUser] Error notifying Hub of activity: HTTP 403: Forbidden
[E 2025-05-29 14:08:39.819 JupyterHubSingleUser] Error notifying Hub of activity: HTTP 403: Forbidden
[I 2025-05-29 14:08:40.103 ServerApp] 200 GET /user/a/api (@192.168.0.12) 2.39ms
[I 2025-05-29 14:08:40.334 ServerApp] 302 GET /user/a/ -> /user/a/lab? (@::ffff:172.30.1.2) 0.64ms
[I 2025-05-29 14:08:40.432 ServerApp] 302 GET /user/a/lab -> /hub/api/oauth2/authorize?client_id=jupyterhub-user-a&redirect_uri=%2Fuser%2Fa%2Foauth_callback&response_type=code&state=[secret] (@::ffff:172.30.1.2) 2.19ms
[W 2025-05-29 14:08:40.700 ServerApp] Failed to check authorization: [401] No permission -- see authorization schemes
[W 2025-05-29 14:08:40.700 ServerApp] {"error": "invalid_client"}

```

If it’s working for you there must be something else. Please can you share you _entire_ configuration and deployment information?

---

<div class="post-metadata">

**Author:** ![paolo](https://avatars.discourse-cdn.com/v4/letter/p/6f9a4e/32.png) [@paolo](https://discourse.jupyter.org/u/paolo)\
**Post date:** [June 17, 2025, 7:59am UTC](https://discourse.jupyter.org/t/is-jupyterhub-api-token-actually-needed/35626/4 "2025-06-17T07:59:28Z")

</div>

@manics How did you unset `JUPYTERHUB_API_TOKEN` in your test?

---

<div class="post-metadata">

**Author:** ![manics](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/manics/32/85_2.png) [@manics](https://discourse.jupyter.org/u/manics)\
**Post date:** [June 21, 2025, 12:07pm UTC](https://discourse.jupyter.org/t/is-jupyterhub-api-token-actually-needed/35626/5 "2025-06-21T12:07:30Z")

</div>

The easiest way is to unset it in a startup script:

```python
c.Spawner.cmd = [
    "sh",
    "-c",
    "unset JPY_API_TOKEN JUPYTERHUB_API_TOKEN; jupyterhub-singleuser"
]

```
