# The signing key

The key that signs the browser companion's session tokens: made on first start, kept across restarts, or yours through CLERK_TWIN_PRIVATE_KEY_FILE.

The simulator signs session tokens with the key `CLERK_TWIN_PRIVATE_KEY_FILE` names. Without that variable, it makes an RSA key on its first start and keeps it in its data folder. It signs with the same key on every later start, so tokens issued earlier still verify. Your site reads the key's public half from `/_twin/config` or the JWKS, so it needs no key file either.

The data folder is `RYSTIC_DATA_DIR`, which the container image sets to `/var/lib/rystic/data`:

| How the simulator runs | The key |
|---|---|
| a container that restarts (`docker compose restart`) | stays the same |
| a container recreated with a named volume at `/var/lib/rystic/data`, as a stack from `rystic export compose` or `rystic compose` mounts | stays the same |
| a container recreated without that volume, or after `docker compose down -v` removes it | is new |
| a process with `RYSTIC_DATA_DIR` unset, or set to a folder it cannot write | is new at each start, and the simulator prints a warning saying why |

To see the key kept, start the simulator on a data folder, stop it and start it again on the same folder:

```bash
DATA=$(mktemp -d)
KEEP_URL=$(rystic run clerk-twin --runner native -d --name keep --port 0 --env RYSTIC_DATA_DIR="$DATA" --json | jq -r .data.url)
FIRST=$(curl -s "$KEEP_URL/v1/jwks" | jq -r '.keys[0].kid')
rystic stop keep > /dev/null
KEEP_URL=$(rystic run clerk-twin --runner native -d --name keep --port 0 --env RYSTIC_DATA_DIR="$DATA" --json | jq -r .data.url)
[ -n "$FIRST" ] && [ "$(curl -s "$KEEP_URL/v1/jwks" | jq -r '.keys[0].kid')" = "$FIRST" ] && echo "same key"
# -> same key
ls "$DATA"
# -> clerk-browser-key.pem
rystic stop keep > /dev/null
```

`rystic export compose` and `rystic compose` give every simulator service a named volume, `rystic-<service>-data`, at `/var/lib/rystic/data`. In a Compose file you write yourself, mount one on the Clerk simulator's service:

```yaml
services:
  clerk:
    volumes:
      - clerk-data:/var/lib/rystic/data
volumes:
  clerk-data: {}
```

A kept key the simulator cannot read, or that is not an RSA key of at least 2048 bits, stops the simulator at start, with an error naming the file. Delete the file to make a new key.

---

Source: https://www.rystic.ai/docs/simulators/clerk/features/signing-key · Markdown: https://www.rystic.ai/docs/simulators/clerk/features/signing-key.md
