Prerequisites
- A running suchi instance.
- A user account (yours, or a dedicated service account — see §5). Local login or OIDC — either works.
curlandjqfor the walkthrough; whatever your app uses in production.
1. Mint a token
Three ways. Pick the one that fits your workflow.From the browser session
If you’re logged in as a normal user, mint via/api/tokens/:
token value now. It is returned exactly once and
never persisted in plaintext — only sha256(token) hits the DB.
From the CLI (username + password)
The mobile-compat endpoint. Same shape mobile apps use on first connect.documents:read,documents:write
scopes. Use /api/tokens/ if you need narrower scopes.
From OIDC
If OIDC is enabled, complete the OIDC login flow in a browser first (cookies get set). Then use the “browser session” recipe above —/api/tokens/ accepts any authenticated principal, cookie or token
alike.
2. Attach the token to requests
Two accepted headers:Token is suchi’s canonical scheme. Bearer is accepted for
convenience since many HTTP clients default to it. When OIDC is
also enabled, disambiguation is by shape: suchi tokens are exactly
64 lowercase hex chars; anything else with Bearer falls through
to the OIDC authenticator.
Every response carries an X-Request-Id header — capture it in
your app’s error logs. When you file a bug, that’s the string that
lets us grep the server side.
3. Verify
Quick sanity check:kind=token confirms the auth chain resolved via the API token.
role=member reflects the underlying user’s role.
Now exercise a real endpoint:
401 unauthorized — token is wrong or has been revoked.
If you get 403 forbidden — token’s scopes don’t cover this action;
mint a wider token.
4. Scope narrowing
The closed scope vocabulary:
Session-authed callers (browser cookie / OIDC) can mint any scope.
Token-authed callers can only mint tokens whose scopes are a
subset of their own — no privilege escalation via daisy-chain.
Best practice: mint the narrowest possible scope. A backup cron
that only reads gets
documents:read. A one-way webhook consumer
that files new docs gets documents:write. An agent claim/act
worker gets agent:tasks.
5. Service accounts
For non-human integrations, create a dedicated user rather than minting from an admin’s personal account. Admin →/admin → Users
→ New; email like svc-backup@internal, no password (they’ll
never log in interactively), then mint a token from the browser
session after impersonation. Rotating an integration’s credentials
now doesn’t touch a real human.
6. Rotation
Tokens have no built-in expiry. Rotate by minting a new one and deleting the old:- Personal integrations: rotate yearly.
- Service accounts: rotate on team turnover or every 90 days, whichever comes first.
- After a suspected leak: revoke immediately, mint a new one, investigate.
7. Revocation
Two paths:- Self-service:
DELETE /api/tokens/{id}from any of the token’s own future calls, or from the user’s browser session. - Admin override: an admin can revoke any token via the same endpoint.
auth_tokens lookup
(no cache — every request re-checks).
8. Audit trail
Every mint + revoke lands inaudit_events with the actor
(user:5 or token:42), action (api_token.create /
api_token.revoke), and request id.
Every mutation performed by a token is audit-logged with
Actor.kind = token, Actor.user_id = <the owner>. When you’re
answering “who did X” a week later, the token’s name (recorded
at mint time on the row) makes it obvious which integration was
responsible.
Common pitfalls
- Storing the token in the app’s own DB unencrypted. The token
IS a credential. Treat it like a password. Env vars, k8s
secrets, macOS keychain,
_FILEmount — any of those. - Sharing a single token across N integrations. When one leaks, you rotate everyone. One integration, one token.
- Using an admin’s token for automation. Every action becomes attributable to a human who didn’t do it. Create a service account.
Related
- Connect an MCP client — same token flow, MCP-shaped consumer.
- Agent surface — for task-claim/act workers with the
agent:tasksscope. - API reference — the full endpoint list.
- Permissions — ACL layer that sits on top of the auth chain. A token authenticates you; ACLs decide what you can see once you’re through.