Auth tokens

Mint short lived access tokens for trusted backends and anonymous visitors.

Auth tokens let a trusted backend mint an Assistant Cloud access token for a workspace, or let a browser begin and continue an anonymous session. The backend route is on https://backend.assistant-api.com and uses an API key. The anonymous routes use the project frontend host and have no Authorization header; see Conventions for hosts and shared error shapes.

The token response

FieldTypeMeaning
tokenstringThe HS256 access token returned by the trusted backend route.
access_tokenstringThe HS256 access token returned for an anonymous session.
refresh_token.tokenstringThe anonymous refresh token. It starts with refresh_0.
refresh_token.expires_atISO 8601When the anonymous refresh token expires. Its lifetime is 30 days from creation or its latest successful refresh.

Every access token has project_id and workspace_id claims. It also has sub for the user, an iss for the project's frontend host, iat for when it was minted, nbf ten seconds before iat, and exp five minutes after iat.

Mint a backend access token

POST /v1/auth/tokens
FieldTypeRequiredRules
AuthorizationheaderyesBearer sk_aui_proj_…. This route accepts an API key only.
Aui-Workspace-IdheaderyesThe workspace the token represents.
Aui-User-IdheadernoThe user in the token's sub claim. It defaults to __SYSTEM__.

This route has no request body. Call it from the backend host, not from a browser.

curl
curl https://backend.assistant-api.com/v1/auth/tokens \
  -X POST \
  -H "Authorization: Bearer $ASSISTANT_API_KEY" \
  -H "Aui-Workspace-Id: workspace_123"
Response
{ "token": "ey…" }
StatusBodyWhen
200{ "token": "<HS256 JWT>" }The access token was minted.
403{ "error": "This endpoint may only be accessed from the backend" }The credential was not an API key.
401 or 403An authentication error.The API key or required API key headers were not accepted. See Conventions.

Minting a token does not create a user, workspace, thread, or refresh token. It may record the API key's last use in the background. Repeating the request produces another access token with a new issuance time.

Start an anonymous session

POST /v1/auth/tokens/anonymous
FieldTypeRequiredRules
AuthorizationheadernoDo not send a credential. The project is selected from the request host.
Request bodybodynoThis route has no body.

The route permits 30 requests per 60 seconds for each client IP address. A limited request has a Retry-After: 60 header.

curl
curl https://proj-0ltyjcuaxpv1.assistant-api.com/v1/auth/tokens/anonymous \
  -X POST
Response
{
  "refresh_token": {
    "token": "refresh_0…",
    "expires_at": "2026-10-17T09:30:00.000Z"
  },
  "access_token": "ey…"
}
StatusBodyWhen
200{ "refresh_token": { "token", "expires_at" }, "access_token" }An anonymous identity and its tokens were created.
403{ "error": "Invalid issuer format or projectId" }The request host does not identify a project.
403{ "error": "Anonymous access is not allowed" }The project does not permit anonymous sessions.
404{ "error": "Project not found" }The host identifies no live project.
429{ "error": "rate_limited" }The client IP exceeded 30 requests in 60 seconds.

On success, Assistant Cloud creates a usr_anon_0… identity and uses it as both the user id and workspace id. It creates a refresh token row that expires 30 days later, then returns a five minute access token. The project policy is checked again as the refresh token is created, so a policy change during the request still answers Anonymous access is not allowed.

Refresh an anonymous session

POST /v1/auth/tokens/refresh
FieldTypeRequiredRules
refresh_tokenstringyesMust be nonempty and start with refresh_0. Unknown body keys are ignored.

The route has no credential and identifies the project from the request host. It permits 120 requests per 60 seconds for each client IP address. A limited request has a Retry-After: 60 header.

curl
curl https://proj-0ltyjcuaxpv1.assistant-api.com/v1/auth/tokens/refresh \
  -H "Content-Type: application/json" \
  -d '{ "refresh_token": "refresh_0…" }'
Request
{ "refresh_token": "refresh_0…" }
Response
{
  "refresh_token": {
    "token": "refresh_0…",
    "expires_at": "2026-10-17T09:30:00.000Z"
  },
  "access_token": "ey…"
}
StatusBodyWhen
200{ "refresh_token": { "token", "expires_at" }, "access_token" }The anonymous session was refreshed.
400{ "success": false, "error": … }refresh_token is missing or empty.
403{ "error": "Invalid refresh token format" }The token does not start with refresh_0.
403{ "error": "Invalid refresh token" }No live anonymous token for an anonymous enabled project matches.
403{ "error": "Invalid issuer format or projectId" }The request host does not identify a project.
403{ "error": "Anonymous access is not allowed" }The project does not permit anonymous sessions.
404{ "error": "Project not found" }The host identifies no live project.
429{ "error": "rate_limited" }The client IP exceeded 120 requests in 60 seconds.

Refresh is idempotent for identity. The refresh token is not rotated. Its expiry is moved forward to 30 days from the successful refresh, so a client that loses the response can retry without receiving a different anonymous identity.