Skip to main content
Every non-browser integration talks to suchi over the same REST surface via a scoped API token. Mobile apps, cron scripts, and custom shell tools all use the same pattern. This guide walks a fresh integration through the token dance: generate/fetch → attach → verify → rotate → revoke. Select a filing system before creating credentials. UI token creation captures that system; API creation/password exchange can use ?system=S02, with omission targeting original system 1. The resulting token’s binding is its default and ceiling, so existing unqualified client calls stay in S02. A conflicting explicit system is unavailable, even for an admin token. Scope, active membership and document permissions remain additional gates. Use a new token to change systems; membership removal revokes old credentials and re-admission never revives them.

Prerequisites

  • A running suchi instance.
  • A user account that can authenticate: a local account with a password, or an OIDC identity. See Service accounts.
  • curl and jq for the walkthrough; whatever your app uses in production.

1. Get a token

Three ways. Pick the one that fits your setup.

From the browser session

If you’re logged in as a normal user, Settings can create a named Read only or Read & write token. The equivalent API call uses /api/tokens/:
Copy the token value now. It is returned exactly once and never persisted in plaintext — only sha256(token) hits the DB.

From the CLI (email + password)

The direct credential-exchange endpoint is useful for a one-shot setup when OIDC is not configured.
This generates a token with the default documents:read,documents:write scopes. Use /api/tokens/ from a browser or OIDC session 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 browser and OIDC sessions, while API-token credentials are intentionally rejected. OIDC deployments do not expose the local password-exchange endpoint.

2. Attach the token to requests

Two accepted headers:
Token is suchi’s preferred 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:
If you get 401 unauthorized — token is wrong or has been revoked. If you get 403 forbidden — token’s scopes don’t cover this action; generate a wider token.

4. Scope narrowing

The closed scope vocabulary: Browser and OIDC sessions can mint any scope in this vocabulary. API tokens cannot call the token-management endpoints. Best practice: generate the narrowest possible scope. A backup cron that only reads gets documents:read; an importer that files new documents gets documents:write.

5. Service accounts

For non-human integrations, use a dedicated identity rather than an admin’s personal account. Create a member with a strong random local password, sign in as that account once, and mint its token. A dedicated OIDC identity works too. Suchi has no user impersonation or admin-side token minting. A local account without a password cannot sign in, and disabling the token’s owner immediately invalidates the token. Store the bootstrap password like any other credential, or remove local-password access after establishing a supported OIDC login.

6. Rotation

Tokens have no built-in expiry. Rotate from an authenticated browser or OIDC session by generating a new one and deleting the old: The commands below assume SUCHI_SESSION contains the signed-in browser’s suchi_session cookie value.
Recommended cadence:
  • Personal integrations: rotate yearly.
  • Service accounts: rotate on team turnover or every 90 days, whichever comes first.
  • After a suspected leak: revoke immediately, generate a new one, investigate.

7. Revocation

Two paths:
  • Self-service: DELETE /api/tokens/{id} from the user’s browser or OIDC session.
  • Admin override: an admin browser or OIDC session can revoke any token via the same endpoint.
Revocation is immediate. Subsequent requests carrying the revoked token fail authentication because every request checks the token table without a cache.

8. Audit trail

Every generation and revocation lands in audit_events with the session user as actor, the api_token.create or api_token.revoke action, and the 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 generation 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, _FILE mount — 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.
  • Connect an MCP client — same token flow, MCP-shaped consumer.
  • 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.