Skip to content

How to authenticate and keep a session alive

Mint, refresh, and revoke workspace tokens, and handle expiry without surprises.

Updated View as Markdown

Authentication has two tiers. This guide covers moving between them and keeping a session healthy.

Tenant credentials

Two headers, on exactly five routes — creating, listing, and deleting workspaces, reading quota, and minting a token:

-H "X-Api-Key: $API_KEY" -H "X-Api-Secret: $API_SECRET"

Missing or wrong credentials return 401 with code bad_api_key.

Mint a token

curl -X POST "$API_URL/auth/token" \
  -H "X-Api-Key: $API_KEY" \
  -H "X-Api-Secret: $API_SECRET" \
  -H "content-type: application/json" \
  -d '{"workspace":"demo","password":"…","scopes":["read","sign"]}'

scopes is optional; omitting it grants ["read","write","sign"]. Request the narrowest set you need — see Scopes and permissions.

A 201 returns the token and its expiry:

{
  "token": "eyJhbGciOi...",
  "expiresAt": "2026-08-18T12:34:56.000Z",
  "workspace": "demo",
  "scopes": ["read", "sign"]
}

Use it as a bearer token on every other route:

-H "Authorization: Bearer $TOKEN"

Refresh before the idle clock runs out

curl -X POST "$API_URL/auth/token/refresh" \
  -H "Authorization: Bearer $TOKEN"

The body must be empty — sending anything else returns 400 with invalid_body. The response adds sessionExpiresAt, the absolute ceiling that refresh cannot move:

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

Each refresh returns a new token for the same lease. Replace the one you hold — but note the previous JWT is not cancelled by the exchange. It keeps working until its own expiresAt, because refresh extends the lease rather than rotating it. Treat refresh as buying time, never as containing a leak.

Handle expiry

An expired session returns 401 with session_expired. The recovery is always the same: mint a new token with the workspace password and retry. A robust client treats this as routine rather than exceptional.

Note that refresh cannot rescue a session past its absolute ceiling — once sessionExpiresAt is in the past, only a fresh mint works.

Revoke when finished

curl -X DELETE "$API_URL/auth/token" \
  -H "Authorization: Bearer $TOKEN"

Returns 204. This revokes the lease of the token you sent, and only that one. Other tokens minted for the same workspace keep working — the workspace locks when its last lease goes.

That makes revoke the tool for containing a specific token: send the compromised one with itself. It is not a way to end everything at once.

Failures worth handling

Code Status What happened
bad_api_key 401 Tenant credentials missing or wrong
bad_password 401 Workspace password wrong
workspace_not_found 404 No such workspace for this tenant
session_expired 401 Idle or absolute clock elapsed
scope_denied 403 Valid token, but the scope was not granted
mint_rate_limited 429 Too many mint attempts for this tenant
session_capacity_exceeded 429 Too many workspaces open at once
export_disabled 403 Asked for export without an operator-registered key
Navigation

Type to search…

↑↓ navigate↵ selectEsc close