Device tokens
What a device token is, and how to rotate it or revoke an extra one from the CLI.
Every device that runs ch device-server authenticates with a device token — a credential created automatically the first time the server starts, and never asked for again. This page covers what a device token is, what happens if a device gets displaced by an unexpected second connection, and the two ways to remove a token: rotating it or revoking it.
What a device token is
ch device-server mints its device token itself the first time it runs on a machine — see How do I add a device? for the full first-run walkthrough. The token is written straight to the file described in Running the device server as a service, under “What the device server needs at startup.” It’s never displayed on screen, at first run or afterward. CodeHerder keeps no copy of it, so it can’t be shown to you later. If the token file is lost or you need a new token, rotate it (below). Every restart after first run just reads the saved file and reconnects.
A token mint is logged in the device’s activity history only if the device already has a workspace at that moment. When you register a device by running ch device-server yourself, the first token is minted before the device is linked to a workspace, so that first token isn’t logged. A device launched from the app already has its workspace, so its first token is logged. A token minted later, by rotating, is always logged.
Archiving a device (see Managing your devices) revokes every token it holds and disconnects it. Restoring the device does not bring those tokens back, so a restored device needs a fresh one. Rotate one (below), same as any other lost or compromised token.
Not the same as your other credentials
A device token is one of three separate credentials, each with its own job:
- An API key (
CH_TOKEN) authenticates a member — human or agent — to thechCLI or the API directly. See Credentials and profiles. - A device token (this page) authenticates a machine running
ch device-serverto CodeHerder. - Workspace secrets store your own encrypted credentials — API keys, database passwords, and the like — for agents to use inside a task. See Secrets.
Rotating one of these has no effect on the others.
One live connection per device
A device holds exactly one live connection to CodeHerder at a time. If a second connection authenticates as the same device while the first is still active, CodeHerder closes the older one and lets the newer one take over. The device never runs two connections at once, and it never stays caught between two.
When that happens, CodeHerder drops a message in the device owner’s inbox. Check the Messages page, or ch msg inbox, in the workspace the device was first linked to — that’s the only place the alert goes, even if the device is now linked to other workspaces too. The message names the device’s id and both connections’ IP addresses, plus the command to rotate the token if you need it. CodeHerder sends this message on every takeover, whether or not anything looks wrong.
This isn’t always a sign of trouble. The same thing happens after an ordinary reconnect, following an unclean shutdown, a lost network, or restarting the device server twice in quick succession, because the old connection is still technically live until CodeHerder notices it’s gone. It also happens if you run a second ch device-server on a different machine using a copied token file: CodeHerder has no way to tell that apart from a real takeover. A second ch device-server that uses the same device folder on one machine refuses to start, so this mix-up needs two separate device folders, such as two machines, two home folders, or two containers.
Before assuming a token has leaked, compare the two IP addresses in the message. If both look like machines and networks you recognize, it was almost certainly just a reconnect. If the newer IP is unfamiliar, treat it as a compromise and rotate the token right away.
Rotate, or revoke an extra token
Through the CLI, a device normally holds exactly one live token: registration mints it, and rotating replaces it with a new one. That covers almost every case. If you suspect a device’s token has leaked, rotate it.
A device only ends up with more than one live token if someone minted an extra one for it directly, separately from the normal registration flow. If that’s your situation, and you know which token you want gone without disturbing the other, revoke it by id instead of rotating.
- Rotate when you’re not sure how many tokens the device holds, or you just want the device’s credential replaced. Rotating revokes every token the device holds and leaves the device offline until it’s given the new one.
- Revoke when the device holds more than one live token and you want to remove one of them by id, without knocking out the token still in use. Revoking removes exactly that one token and leaves the rest alone.
Revoking the device’s only live token has the same effect as rotating, minus the replacement. The device goes offline, because it no longer has a credential to connect with. Only rotate or register again gives it a new one.
Rotating a device token
If you suspect a device’s token has leaked (the alert above named an IP you don’t recognize, or the token file was exposed some other way), rotate it:
ch device rotate-token <device>
You can run this if you’re the device’s owner and you still hold at least admin rank in the workspace the device was linked to first, or if you’re an owner or admin of that workspace yourself. Being an owner or admin of a workspace the device was added to later doesn’t grant this. If the device isn’t linked to any workspace yet, being its owner is enough, though an unlinked device can’t connect to anything either way, so this mostly matters for the moment right after first registration. It’s a human-only command. Agents can’t run it, and it’s refused even for a human working from a session you started on a device, so run it from your own login.
Rotating revokes every existing token for the device immediately, with no grace period where both the old and new token work, and closes the device’s live connection right away. The command then prints a brand-new token, shown once, along with the exact command to save it on the device:
umask 077 && printf '%s\n%s\n' <deviceId> '<token>' > ~/.codeherder/device.token
That command writes to the default token path. If the device runs with a custom --token-file, change the path in the printed command to match before you run it there.
The device stays offline until it has the new token. In most cases you don’t need to do anything else: ch device-server checks its token file every time it retries a connection, so once you’ve saved the new token on the device, it reconnects on its own, typically within about a minute. Restarting ch device-server isn’t required; it just makes the reconnect happen immediately instead of on the next retry.
Revoking an extra token
If a device holds more than one live token and you only want to remove one of them, revoke it by id:
ch device revoke-token <device> <tokenId>
The same permission rule as rotating applies: you need to be the device’s owner while still holding at least admin rank in its first-linked workspace, or an owner or admin of that workspace yourself. It’s human-only, same as rotating.
Revoking always closes the device’s live connection, even when another token is still live. CodeHerder can’t close just one token’s share of a connection, only the whole thing. If another live token remains, the device reconnects on that one right away, so you won’t see it go offline the way a rotate does. If the token you revoked was the device’s only one, it stays offline instead, just like after a rotate, but with no replacement token printed.
It’s safe to run more than once. Revoking a token that’s already revoked still succeeds and does nothing further — no second disconnect, no second log entry.
There’s no command that lists a device’s tokens, and no token screen in the app. A token id shows up in two places: the tokenId field in ch device rotate-token --json’s output, and the device’s activity history, where each logged mint or revoke carries the token id (see above for when a first token isn’t logged):
ch activity workspace <workspace> --type device.token_minted --subject-id <deviceId> --json
Two things to get right here: --subject-id wants the device’s full id, not its hostname (ch device show <device> prints it), and the events live in the device’s first-linked workspace feed, so point ch activity workspace at that workspace. You also need --json — the plain-text table doesn’t show tokenId, only the JSON payload does.
Why not just delete the token file and re-register?
Deleting the token file and letting ch device-server self-register again creates a brand-new device — a new identity, disconnected from the old one’s workspace links and history. The old device is left behind, still showing whatever state it was in. Rotating keeps the same device and everything attached to it; only the credential changes.
Signs a device token has gone bad
If a device’s token stops being accepted — because it was rotated from elsewhere, or its last remaining live token was revoked — the device can no longer connect, so it shows Offline and stops picking up work. (Revoking one token out of several doesn’t do this: the device just reconnects on another one it still holds.)
Its health snapshot won’t show a failing check for this. The device only pushes a snapshot while it has a live connection — on connect, when something changes, and periodically in between — so once the connection is gone, the snapshot simply stops updating and keeps showing whatever it last reported while the token still worked. The device server itself keeps retrying in the background and logs the rejection locally on that machine. If a device is Offline and you don’t see an obvious cause, rotating its token (above) and saving the new one on the device is the fix. See Managing your devices for how to read the health snapshot and its checks.
Related guides
- How do I add a device? — connect a machine for the first time
- Managing your devices — device health, readiness checks, and troubleshooting
- Credentials and profiles — your own API key, separate from any device’s token
- Agents and the CLI — launch configs and where an agent runs
Last updated