# JupyterHub DockerSpawner not preserving API token when attempting to spawn container with NB\_USER

**URL:** <https://discourse.jupyter.org/t/jupyterhub-dockerspawner-not-preserving-api-token-when-attempting-to-spawn-container-with-nb-user/13184>\
**Category:** JupyterHub\
**Tags:** help-wanted, docker\
**Created:** [February 26, 2022, 7:37pm UTC](https://discourse.jupyter.org/t/jupyterhub-dockerspawner-not-preserving-api-token-when-attempting-to-spawn-container-with-nb-user/13184 "2022-02-26T19:37:48Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![shapeshifter](https://avatars.discourse-cdn.com/v4/letter/s/bbce88/32.png) [@shapeshifter](https://discourse.jupyter.org/u/shapeshifter)\
**Post date:** [February 26, 2022, 7:37pm UTC](https://discourse.jupyter.org/t/jupyterhub-dockerspawner-not-preserving-api-token-when-attempting-to-spawn-container-with-nb-user/13184/1 "2022-02-26T19:37:48Z")

</div>

Hey folks,

I am running into an issue where I am trying to deploy an instance of JupyterHub using DockerSpawner (more specifically, SwarmSpawner) in which I want to launch notebook containers (the Jupyter Docker Stacks in particular) as the user who logs into the Hub, rather than the default jovyan user.

**Situation** :

Instead of launching each notebook container as jovyan, I wish to spawn each container through JupyterHub as the particular user logging into to the system. Running the container without the hub, this is just:

```auto
docker run -it --rm --user root \
    -e NB_USER=user \
    -e CHOWN_HOME=yes \
    -w "/home/${NB_USER}"
    jupyter/base-notebook

```

Trying to port this logic over to JupyterHub/DockerSpawner, I’ve tried the following:

I created a custom authenticator that implements a `pre_spawn_start` function that will take the user who has logged in and update the spawner’s container spec to launch as said user:

```python
async def pre_spawn_start(self, user, spawner):
    spawner.extra_container_spec.update(
        {
            "user": "root",
            "workdir": f"/home/{user.name}",
            "env": {
                "NB_USER": user.name,
                "CHOWN_HOME": "yes",
            }
        }
    )

```

I pass this authenticator in to the `jupyterhub_config.py` file:

`c.JupyterHub.authenticator_class = CustomAuthenticator`

What happens next is after launching JupyterHub and logging in, depending on the approach, one of two things will happen:

1. The default command for the notebook image is `start-notebook.sh`, in which it will look for the `JUPYTERHUB_API_TOKEN` environment variable; if it exists, it will attempt to execute `start-singleuser.sh` to launch the notebook server. Otherwise it will launch a jupyter (lab) instance. When the container is started as jovyan (the default in the stack), this API token is passed without issue and `start-singleuser.sh` executes and communicates with the Hub with no issue. Changing the user to `NB_USER` and launching the notebook container, the API token does not seem to be passed as an environment variable to the container, which causes `start-notebook.sh` to launch a local instance of JupyterLab - this does not communicate back to the Hub and thus when the container spawns, I cannot continue further, getting a 404 error.

2. If I change the default cmd to something like `jupyterhub-singleuser` instead, the notebook container will fail to spawn after 30 seconds. Inspecting the logs, it compains with the following error:

`JUPYTERHUB_API_TOKEN env is required to run jupyterhub-singleuser. Did you launch the service manually?`

The `start.sh` script in the docker stacks, upon creating the new user based on NB\_USER, launches with the `--preserve-env` option, so I’m a bit stuck here as to how I could proceed. Has anybody tried this particular endeavor?

---

<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:** [February 27, 2022, 11:26pm UTC](https://discourse.jupyter.org/t/jupyterhub-dockerspawner-not-preserving-api-token-when-attempting-to-spawn-container-with-nb-user/13184/2 "2022-02-27T23:26:37Z")

</div>

I suspect this might be overriding the environment:

> [@shapeshifter](#):
>
> ```auto
> spawner.extra_container_spec.update(
> {
> "user": "root",
> "workdir": f"/home/{user.name}",
> "env": {
> "NB_USER": user.name,
> "CHOWN_HOME": "yes",
> }
> }
> )
> 
> ```

Have you tried setting the environment using the spawner configuration instead?

> **[Authenticators](https://jupyterhub.readthedocs.io/en/stable/reference/authenticators.html#using-auth-state)**
>
> The Authenticator is the mechanism for authorizing users to use the Hub and single user notebook servers. The default PAM Authenticator: JupyterHub ships with the default PAM-based Authenticator, f...

---

<div class="post-metadata">

**Author:** ![shapeshifter](https://avatars.discourse-cdn.com/v4/letter/s/bbce88/32.png) [@shapeshifter](https://discourse.jupyter.org/u/shapeshifter)\
**Post date:** [February 28, 2022, 7:40pm UTC](https://discourse.jupyter.org/t/jupyterhub-dockerspawner-not-preserving-api-token-when-attempting-to-spawn-container-with-nb-user/13184/3 "2022-02-28T19:40:41Z")

</div>

I had initially tried setting it through `c.DockerSpawner.environment`, but it seems that takes effect too late to make a difference. I can confirm that what you proposed does the trick! I was under the assumption that the container\_spec var was only for the `docker run` (or equivalent) command environment variables, but I guess that is the global set instead. Appreciate the help!
