Authentication
How tokens work, what's public, and what to expect when things go wrong.
Endpoint schemas and parameter details live in the API Reference. This page covers authentication behavior — how tokens work, what's public, and what to expect when things go wrong.
Token Transport
All protected endpoints require an access token. Two transports are supported:
Authorization header (programmatic clients):
Authorization: Bearer <access_token>Session cookie (browser clients):
Cookie: session=<access_token>The Bearer prefix is case-sensitive — bearer is not accepted. The token is a base64-encoded 32-byte value issued by the login flow. It is opaque — do not parse or decode it. When both are present, the Authorization header takes precedence.
Where To Get a Token
Tokens are issued at the end of the OPAQUE login handshake:
POST /auth/opaque/authenticate-start— send blinded login requestPOST /auth/opaque/authenticate-finish— complete handshake, receiveaccess_tokenandrefresh_token
The access token expires after 15 minutes. When it expires, refresh it — do not re-authenticate.
Token Refresh
POST /auth/tokens/refresh exchanges a valid refresh token for a new access token and a new refresh token. This endpoint requires no Authorization header — the caller's access token may already be expired.
This endpoint also requires the X-Literal-Request: 1 header — calls without it return 403 CSRF_REQUIRED. The header is the only protection against cookie-authenticated cross-site requests, since the browser sends literal_rt automatically.
Browser clients send the refresh token automatically via the literal_rt HttpOnly cookie. Programmatic clients pass it in the request body.
The old refresh token is permanently revoked on each call. If an attacker replays a stolen refresh token after the legitimate client has already rotated, the server rejects the stale token with 401.
For the full OPAQUE registration and login protocol, see the Authentication reference under Getting Started.
Token Expiry: 401 vs. 403
| Status | Meaning | What to do |
|---|---|---|
401 Unauthorized | Token is missing, malformed, expired, or revoked | Refresh the token via /auth/tokens/refresh. If that also fails, re-authenticate. |
403 Forbidden | Token is valid, but you lack permission for this resource | Check your role (e.g. entity admin vs. member). This is not a token problem. |
The API will never return 401 for a permission issue or 403 for an expired token. The distinction is strict.
Public (Unauthenticated) Endpoints
The API enforces deny-by-default authentication. Every endpoint is protected unless explicitly opted out. The following endpoints require no Authorization header:
Auth
| Endpoint | Why it's public |
|---|---|
POST /auth/challenges | OPRF email blind index evaluation |
POST /auth/opaque/register-start | Registration step 1 |
POST /auth/opaque/register-finish | Registration step 2 |
POST /auth/opaque/authenticate-start | Login step 1 |
POST /auth/opaque/authenticate-finish | Login step 2 |
GET /auth/recovery | Fetch UMK backup |
POST /auth/recovery | Complete account recovery |
POST /auth/tokens/refresh | Token rotation (body-token auth, no session) |
Platform
| Endpoint | Why it's public |
|---|---|
GET /public-keys/server | Clients need the platform public key to wrap DEKs before they have a session |
POST /verifications | Seal and capability token verification must work without a session |
Grants
| Endpoint | Why it's public |
|---|---|
GET /grants | Anonymous grant discovery via view tags — recipients don't need a session to check for incoming grants |
DELETE /grants/{id}/claim | Grantee self-revoke via claim token — authenticates by claim token, not session |
Users
| Endpoint | Why it's public |
|---|---|
GET /users/{userId}/public-keys | Grant senders need to look up recipient public keys without the recipient being online |
All other endpoints require a valid session token.
See Also
- Session Lifecycle — session states, token refresh, and logout
- Getting Started — Authentication — full OPAQUE registration and login walkthrough
- OPRF Login — how the blind authentication protocol works end-to-end
Last updated on