Skip to content

Workspaces, tokens, and session lifetime

Why minting a token is the unlock, how sessions expire, and what refresh actually extends.

Updated View as Markdown

A workspace is a password-protected collection of accounts. At rest it is locked, and its contents are unreadable without the password.

A token is the unlock

There is no separate unlock endpoint. POST /v1/auth/token takes the workspace password and returns a bearer token, and that token’s lifetime is the unlock session. While a valid token exists, the workspace is open. Revoke it and the workspace locks again.

This has three consequences worth internalising:

  • The workspace password is presented exactly once per session, at mint time. That call is authenticated by tenant credentials, because it is the only workspace-tier call that has no token yet.
  • DELETE /v1/auth/token revokes the lease of the token that sent it, and only that one. Other tokens on the same workspace keep the session open; it locks when the last lease goes. Minting twice for one workspace gives you two independently revocable tokens, not two copies of one.
  • No workspace-token route takes the workspace in its path. It comes from the token’s claim, so a path and a token can never disagree about which workspace is in play. The tenant-tier routes do use a path slug — they carry no token to disagree with.

Two clocks

A session is bounded by two independent timers, both configured per tenant.

Clock Config Default Meaning
Idle ttl.workspaceIdleSec 15 minutes Time since the last activity on the session. Any authenticated request resets it, not only a refresh.
Absolute ttl.workspaceAbsoluteSec 8 hours Total session lifetime from mint. Refresh does not extend it.

Your operator can set both per tenant, so treat the defaults as the shape of the thing rather than a contract — but they are what applies when nothing is configured.

POST /v1/auth/token/refresh issues a new token and pushes the idle clock out. Its response reports both, so you can see the ceiling coming:

{
  "token": "eyJhbGciOi...",
  "expiresAt": "2026-08-18T12:49:56.000Z",
  "sessionExpiresAt": "2026-08-18T20:15:00.000Z",
  "workspace": "demo",
  "scopes": ["read", "write", "sign"]
}

When sessionExpiresAt arrives, refreshing stops working. Mint a new token with the workspace password instead.

Accounts have their own lock

Locking is two-tiered. Opening the workspace does not necessarily open everything inside it.

  • An account using the shared workspace password unlocks transparently the first time you touch it — but only for as long as its custody window lasts. When that window closes the account locks like any other, and reopening it means calling POST /v1/accounts/{slug}/unlock with the workspace password.
  • An account created with hasOwnPassword: true has its own password and must be unlocked explicitly via POST /v1/accounts/{slug}/unlock. Until then it answers 423 with code account_locked.

Account unlocks have their own absolute timer (ttl.accountAbsoluteSec, typically much shorter than the session) and their own rate limit — repeated failed attempts return 429 with account_unlock_rate_limited, backing off 1, 2, 4, then 8 seconds.

The fifth consecutive failure ends the session. Not just that unlock — the whole workspace session is destroyed, and every other token holding it open starts answering 401 with session_expired. Treat a wrong account password as a stop condition, not something to retry into.

Capacity

Four limits can refuse a mint even when your credentials are perfect.

Three of them share the code session_capacity_exceeded, and error.details names which one you hit:

details.scope Ceiling Default
workspace Live tokens on this one workspace 64
tenant Workspaces your tenant holds open at once (limits.maxUnlockedWorkspaces) 8
process Workspaces open across the whole service, every tenant 32

The process leg is worth knowing about because you cannot fix it: it is not your tenant’s activity that filled it, and revoking your own tokens may not clear it. The workspace leg surprises clients that mint per request instead of reusing a token — sixty-four live leases on one workspace is enough, with no second workspace open at all.

The fourth is the mint rate limit — 429 with mint_rate_limited, per tenant. The charge applies once the request is well formed and names a known workspace, so a tight retry loop against a bad password is counted.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close