Minting is the only workspace-tier operation authenticated by tenant credentials — it is where the workspace password is presented.
POST /v1/auth/token
Mint a workspace token. Auth: tenant credentials. Returns 201.
Request
{
"workspace": "demo",
"password": "a-strong-workspace-password",
"scopes": ["read", "sign"]
}| Field | Type | Required | Notes |
|---|---|---|---|
workspace |
string | yes | Workspace slug |
password |
string | yes | At least 1 character |
scopes |
string[] | no | Defaults to ["read","write","sign"]. 1–4 entries, each ≤32 chars |
Only read, write, sign, and export are grantable. An unrecognised name
returns 400 with invalid_body — unknown scopes are never silently dropped.
Requesting export without an operator-registered key returns 403 with
export_disabled.
Response
{
"token": "eyJhbGciOi...",
"expiresAt": "2026-08-18T12:34:56.000Z",
"workspace": "demo",
"scopes": ["read", "sign"]
}Errors
| Status | Code |
|---|---|
| 400 | invalid_body, invalid_slug |
| 401 | bad_api_key, bad_password |
| 403 | export_disabled |
| 404 | workspace_not_found |
| 429 | mint_rate_limited, session_capacity_exceeded |
POST /v1/auth/token/refresh
Issue a new token and push out the idle clock. Auth: workspace token, any
scope. Returns 200.
Request
The body must be empty. Sending anything else returns 400 with invalid_body.
Response
{
"token": "eyJhbGciOi...",
"expiresAt": "2026-08-18T12:49:56.000Z",
"sessionExpiresAt": "2026-08-18T20:15:00.000Z",
"workspace": "demo",
"scopes": ["read", "sign"]
}sessionExpiresAt is the absolute ceiling. Refresh moves expiresAt; it never
moves sessionExpiresAt. Once the ceiling passes, mint a new token instead.
Each refresh returns a new token — replace the one you hold. Responses carry
cache-control: no-store.
Refreshing does not invalidate the token you sent. It extends the same lease
and issues a fresh JWT for it; the older one keeps working until its own
expiresAt passes. If a token has leaked, refreshing does nothing to contain
it — revoke it.
Errors
| Status | Code |
|---|---|
| 400 | invalid_body |
| 401 | session_expired |
DELETE /v1/auth/token
End the session and lock the workspace. Auth: workspace token, any scope.
Returns 204 with no body.
curl -X DELETE "$API_URL/auth/token" -H "Authorization: Bearer $TOKEN"Related
- Authenticate — the lifecycle as a task
- Workspaces and tokens — the model