Docs · Multi-tenancy
API tokens.
Long-lived bearer tokens for the CLI, MCP service, and CI. Browser sessions use a separate short-lived JWT cookie path. Tokens are scoped, rotatable, and audited; the plaintext is shown once at creation and never again.
Why three auth paths
| Surface | Auth | Lifetime |
|---|---|---|
| Browser console | httpOnly Secure cookie (JWT) on .remoco.dev | 15 min access · 14 day refresh |
| CLI / MCP / CI | opaque pak_* bearer in Authorization: Bearer | configurable expiry, default never |
| Cloud Scheduler | legacy shared service token | (rotation tracked in risks doc) |
Mint a token
Console: Admin → API tokens card → + Mint token. Pick a name (e.g. "wiley laptop"), a surface (cli/mcp/service), and optional expiry in days. The plaintext flashes once with a copy-to-clipboard button; you must check the "I copied it" box to dismiss.
// minted token shape pak_aBcDeFgHi…
API (admin/owner role required):
$ curl -X POST https://api.remoco.dev/v1/api-tokens \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"wiley laptop","surface":"cli","expires_in_days":90}' { "id": "pak-...", "prefix": "pak_aBcDeFg", "scopes": ["read","write"], "surface": "cli", "expires_at": "2026-07-25T22:30:00Z", "token": "pak_aBcDeFgHi..." // only returned here, only this once }
Use a token
CLI:
$ remoco login --token=pak_aBcDeFgHi...
MCP:
$ REMOCO_API_TOKEN=pak_... mcp serve
Direct HTTP:
$ curl -H "Authorization: Bearer pak_..." https://api.remoco.dev/v1/me
Storage
Only SHA-256 of the plaintext lives in Postgres (column token_sha256). The first 12 chars are stored as prefix for UI listings ("pak_aBcDeFg…") so you can identify which token is which without seeing the plaintext.
If you lose the plaintext: mint a new one, update the consumer, then revoke the old. Recovery of the plaintext is not possible by design.
Revoke + delete
Revoke is the soft delete: the row stays for the audit trail, but revoked_at is set and the token fails authentication immediately on the next request.
$ curl -X POST https://api.remoco.dev/v1/api-tokens/pak-abcd1234/revoke \ -H "Authorization: Bearer $ADMIN_TOKEN"
Delete is permanent (the row is gone from Postgres, but the audit events for mint/revoke remain).
Scopes
Default scopes: ["read", "write"]. Service tokens can be minted with ["read", "write", "reconcile"] for Cloud Scheduler-style flows. Custom scopes are an integer-locked list today; see Control-plane API.
Diagnose with remoco doctor
The CLI ships a doctor command that checks credentials, base URL reachability, /v1/me, and tells you what kind of token is in use:
$ remoco doctor ✓ credentials file ~/.remoco/credentials.json (env=prod) ✓ api base url https://api.remoco.dev ✓ api /health 200 in 38ms ✓ auth /v1/me [email protected] · org=doss-labs · role=owner ✓ token format pak (api token) ✓ node version v22.7.0 ✓ gcloud installed for `remoco logs --follow` ✓ git installed for `remoco clone` # 8 passed · 0 failed · 8 total
Risk model
- Plaintext only ever in Cookie / Authorization header / your secret store. Never logged.
- SHA-256 lookups (Postgres index
api_tokens_active_idx) are O(log n), no plaintext on disk. - Rate limiting on /v1/* applies per-org regardless of token type, so a leaked token can't burn the budget unbounded.
- Revoke takes effect on the next request — no token cache.