Subshell Docs
Server

API Keys

The machine credentials: what a subshell's token is, and what a system key is, and why they are different animals.

Two kinds of bearer credential reach the API, both spelled the same way on the wire (Authorization: Bearer subshell_…), and they are deliberately different animals: one is a pane talking to the plane as itself, and the other is a key you mint for your own tooling. Understanding which one you are holding answers most questions about what it can do.

A subshell's own token

When you launch a subshell, the server mints a token for it. You never see this one, and it appears nowhere you manage: the API keys page lists only yours, never these. Its shape:

  • Scoped by a permission map: channels and subshells, each read/write. Not "whatever the owner can do" but a fixed ceiling.
  • 7-day lifetime, self-extending while the subshell's MCP child is running, so a long-lived agent is not cut off mid-task.
  • Dies with the row. Terminate or delete the subshell and its token is revoked instantly. Restarting one, auto or manual, rotates the key in place. The subshell row, not the key, is lifecycle truth: a valid-looking key whose subshell is gone is simply refused.
  • Impersonates its owner narrowly. On per-subshell routes a machine token runs with the admin boost and sharing grants switched off: a pane can act only on its own owner's subshells, never a foreign one, never one merely shared with its owner. Self-report endpoints (attention signals, harness session identity) accept only a subshell's own key acting on its own row. It may mint a WebSocket terminal-attach token too, but only for its own subshell: a pane can drive its own terminal, never another's.

One honest caveat, accepted in the threat model: the token rides in the pane's tmux start command, so it is visible to any local user on the machine that runs the pane. Whoever owns that machine effectively holds its panes' credentials.

System keys

A system key is the long-lived, full-access credential you mint for LAN tooling, scripts, and anything that is not a human at a browser. You create them under Settings → API keys (admins only):

  • Owned by the system service account, with no permission ceiling: every holder is effectively an operator.
  • The plaintext is shown exactly once, at creation. Only a hash is stored, so a lost key cannot be read back: the recovery is to mint a new one and delete the old, which is also how you "rotate" one.
  • Drives terminals, too. A system key can mint a WebSocket attach token for any subshell: each mint names one pane, lives 30 seconds, and is refused anywhere else. Containment is that binding, not a refusal to mint.
  • Disabling is instant revocation: a disabled key authenticates nowhere, immediately. Deleting removes the row.
  • Each key carries a name for identification and a short non-secret preview in listings.

Because these keys hold no ceiling, scope them by practice, not mechanism: mint one per purpose, and keep the one you would reach for at 3 a.m. somewhere safer than a CI variable.

The rule that bounds both kinds

Machine credentials can never manage the instance. Every admin surface (user management, settings writes, system keys, the admin group, plugin and network installs) refuses a bearer credential with 403, even one whose owner is an admin. Bearer actors also read "not an admin" in every response that gates the admin nav. The blast radius of a leaked system key is everything the API does; it is not the instance itself.

Two reads are deliberately instance-wide for bearer credentials, both because a UI needed them:

  • The user roster (GET /api/users) is what lets the sharing picker name people, so any signed-in caller, subshell token included, can read every account's email, display name, role and disabled state.
  • The address list (GET /api/settings/public → trustedOrigins) is what lets the "Subshell for Mobile" dialog offer a phone an address the plane actually answers on.

Both widen visibility, not access: they carry no secret and grant nothing. Their soundness on a trusted network rests on the same ground as the rest of the posture: every signed-in user is someone the operator admitted.

See also

  • System API Keys: minting and using one from your own tooling
  • REST API: what an authenticated caller can drive
  • Users & Roles: the system account that owns your keys, and why it is untouchable
  • The full threat model: the credential table, the forgery defense, and the accepted ps exposure
Edit on GitHub

Last updated on

On this page