# Auth tokens
URL: /docs/cloud/api/auth-tokens

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

> For AI agents: a documentation index is available at [llms.txt](/llms.txt). Use `.md` for canonical markdown pages; `.mdx` is kept as a backwards-compatible alias on supported URL paths.

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](/docs/cloud/api) for hosts and shared error shapes.

## The token response

| Field                      | Type     | Meaning                                                                                                           |
| -------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------- |
| `token`                    | string   | The HS256 access token returned by the trusted backend route.                                                     |
| `access_token`             | string   | The HS256 access token returned for an anonymous session.                                                         |
| `refresh_token.token`      | string   | The anonymous refresh token. It starts with `refresh_0`.                                                          |
| `refresh_token.expires_at` | ISO 8601 | When 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
```

| Field              | Type   | Required | Rules                                                             |
| ------------------ | ------ | -------- | ----------------------------------------------------------------- |
| `Authorization`    | header | yes      | `Bearer sk_aui_proj_…`. This route accepts an API key only.       |
| `Aui-Workspace-Id` | header | yes      | The workspace the token represents.                               |
| `Aui-User-Id`      | header | no       | The 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 https://backend.assistant-api.com/v1/auth/tokens \
  -X POST \
  -H "Authorization: Bearer $ASSISTANT_API_KEY" \
  -H "Aui-Workspace-Id: workspace_123"
```

```
{ "token": "ey…" }
```

| Status         | Body                                                                 | When                                                                                           |
| -------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `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 `403` | An authentication error.                                             | The API key or required API key headers were not accepted. See [Conventions](/docs/cloud/api). |

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
```

| Field           | Type   | Required | Rules                                                                    |
| --------------- | ------ | -------- | ------------------------------------------------------------------------ |
| `Authorization` | header | no       | Do not send a credential. The project is selected from the request host. |
| Request body    | body   | no       | This 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 https://proj-0ltyjcuaxpv1.assistant-api.com/v1/auth/tokens/anonymous \
  -X POST
```

```
{
  "refresh_token": {
    "token": "refresh_0…",
    "expires_at": "2026-10-17T09:30:00.000Z"
  },
  "access_token": "ey…"
}
```

| Status | Body                                                             | When                                               |
| ------ | ---------------------------------------------------------------- | -------------------------------------------------- |
| `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
```

| Field           | Type   | Required | Rules                                                                       |
| --------------- | ------ | -------- | --------------------------------------------------------------------------- |
| `refresh_token` | string | yes      | Must 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 https://proj-0ltyjcuaxpv1.assistant-api.com/v1/auth/tokens/refresh \
  -H "Content-Type: application/json" \
  -d '{ "refresh_token": "refresh_0…" }'
```

```
{ "refresh_token": "refresh_0…" }
```

```
{
  "refresh_token": {
    "token": "refresh_0…",
    "expires_at": "2026-10-17T09:30:00.000Z"
  },
  "access_token": "ey…"
}
```

| Status | Body                                                             | When                                                              |
| ------ | ---------------------------------------------------------------- | ----------------------------------------------------------------- |
| `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.