Skip to content

Handling tokens and key material safely

Which credential administers what, why a revoke only ends the token that sent it, and the deletions and outcomes that cannot be undone.

Updated View as Markdown

This service holds key material. A few habits keep an integration from becoming the weak link.

Never commit these

  • .env.local and any environment file carrying real values
  • config/tenants.json — API keys and secret hashes
  • Workspace directories and service state
  • Tokens, workspace passwords, account passwords
  • Exported key material, including sealed blobs

Credentials

Tenant credentials (X-Api-Key + X-Api-Secret) administer every workspace you own and mint tokens for all of them. They belong on a server you control — never in a browser, mobile app, or anything shipped to a user.

Workspace passwords are unrecoverable. The service cannot reset one or recover a workspace without it. Store them the way you store root credentials.

Workspace tokens are bearer credentials: whoever holds one has the scopes it carries until it expires or is revoked. Treat a token like a password for its whole lifetime.

Scoped API keys are the durable, single-string keys a tenant mints for an end user, bound to one account or wallet. They stay live — and keep their account unlocked — until the service restarts, so a token revoke does not contain one; see API keys. The end user stores the one string (for example in localStorage) and never sees the workspace password.

Ask for the narrowest scope

Scopes are fixed at mint time but cheap to re-mint. A service that only reads and signs should hold ["read","sign"], so a leaked token cannot create or delete anything.

export is not something a workspace token exercises on its own. The two export routes require an Unlimited scoped API key minted with a live inquiry key, and the result is sealed to that key — see Scopes and permissions and Export.

A durable scoped API key is different: DELETE /v1/auth/token is a no-op for it, and it holds its account open until the service restarts or the key is evicted under capacity pressure. There is no per-key revoke, so plan to re-mint after a restart rather than to revoke — see API keys.

Deletion is real

Deleting a workspace or an account destroys the key material inside it. There is no undo and no recovery from the service side.

Deleting a workspace that is currently in use is refused with 409 workspace_in_use. ?force=true overrides that one refusal — it closes the live session and deletes anyway. It overrides nothing else: a 403 from the storage layer stands with or without it. The refusal is the safety rail, so reach for force only when you have established that nothing is mid-operation. See Manage workspaces.

Sealed exports are still key material

A sealed blob is your key, encrypted to the end user’s own inquiry key — the X25519 recipient supplied when the tenant minted the scoped API key. Only the matching private half can open it, and that half stays with the end user, never with the server or the operator. That makes a sealed blob safe from a thief who lacks the private key, and nothing else. Keep it out of logs, issue trackers, chat, and CI artifacts. Give it no longer a retention than you would give the key itself.

Check recipientFingerprint before decrypting: it identifies which key the blob was sealed to.

Guard the private half the way you guard the key material itself. It is the one value that turns every sealed blob you have ever received back into plaintext, and nothing in the service can rotate or revoke it for you.

Handling errors safely

  • Branch on error.code, never on message.
  • Do not log whole request bodies from account creation, unlock, or token mint — they carry passwords and secrets.
  • Keep requestId for support. Every error body carries one, and it also comes back on the x-request-id response header. It is safe to share; the rest of the error may not be.

Signatures

  • A signature is a bearer instrument. The service returns it; broadcasting is yours, so treat a returned signature as sensitive until it is on-chain.
  • Sign a digest or raw bytes only when you built them yourself. The service signs exactly what you send — it does not re-hash or frame a /sign/digest or /sign/bytes payload.

Operational hygiene

  • Run one service instance per state directory. A second instance on the same storage is refused, deliberately, to protect wallet and quota records.
  • Rotate tenant credentials through your operator rather than sharing them across environments.
Navigation

Type to search…

↑↓ navigate↵ selectEsc close