# API tokens

> Create, list and revoke the owf_ API tokens that authenticate requests to the API, the CLI and the MCP server.

API tokens (`owf_…`) authenticate the API, the SDKs, the CLI and the MCP server. A token acts with the role of its member, limited to the token's own role and, optionally, to one zone or one client. See [Authentication](https://developers.openwaf.dev/api/authentication/).

| Operation | Endpoint |
|---|---|
| [List tokens](https://developers.openwaf.dev/api/tokens/#list-tokens) | `GET /v1/orgs/{org}/tokens` |
| [Create token](https://developers.openwaf.dev/api/tokens/#create-token) | `POST /v1/orgs/{org}/tokens` |
| [Revoke token](https://developers.openwaf.dev/api/tokens/#revoke-token) | `DELETE /v1/orgs/{org}/tokens/{id}` |

## List tokens

```http
GET /v1/orgs/{org}/tokens
```

Lists the active API tokens of the organization, never their secrets. `prefix` helps to recognise each one and `last_used_at` tells when it was last used.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns `items`, an array of [APIToken](https://developers.openwaf.dev/api/schemas/#api-token).

| Field | Type | Description |
|---|---|---|
| `items[].id` | string (uuid) | Id. |
| `items[].org_id` | string (uuid) | Organization id. |
| `items[].zone_id` | string (uuid) | Zone id. |
| `items[].user_id` | string (uuid) | User id of the member. |
| `items[].name` | string | Name. |
| `items[].role` | string | Role. One of `owner`, `admin`, `tech`, `readonly`. |
| `items[].prefix` | string | First characters of the secret, to recognise it. |
| `items[].purge_only` | boolean | Can only purge its zone's cache. |
| `items[].created_by` | string | Who created it (actor). |
| `items[].created_at` | string (date-time) | Creation time. |
| `items[].expires_at` | string (date-time) | Expiry time. |
| `items[].last_used_at` | string (date-time) | Last use. |
| `items[].client_id` | string (uuid) or null | Client the token is limited to (roles tech and readonly only); null = the whole organization. |

#### Example

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/tokens" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.listTokens();
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.list_tokens()
```



```json
{
  "items": [
    {
      "id": "11111111-2222-4333-8444-555555555555",
      "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
      "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
      "user_id": "5b8e2a1c-7d3f-4a9e-b6c2-1e4d7f0a3b9c",
      "name": "ci-deploy",
      "role": "tech",
      "prefix": "owf_8Jx2",
      "purge_only": false,
      "created_by": "user:5b8e2a1c-7d3f-4a9e-b6c2-1e4d7f0a3b9c",
      "created_at": "2026-10-27T09:30:00Z",
      "expires_at": "2027-01-25T09:30:00Z",
      "client_id": null
    }
  ]
}
```

## Create token

```http
POST /v1/orgs/{org}/tokens
```

Creates an API token for the caller's own member. Without `role` the token gets the caller's role. It can be limited to one zone (`zone_id`), to one client (`client_id`) or to purging its zone's cache (`purge_only`). See [Limit a token](https://developers.openwaf.dev/api/authentication/#limit-a-token).

The `secret` (`owf_…`) is returned only in this answer: store it right away.

**Required role:** `readonly` or higher. The new token's role cannot be higher than the caller's. Not available to tokens limited to a zone.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Request body

Content type `application/json`.

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | Yes | Name. At most 200 characters. |
| `role` | string | No | Role of the token; by default the caller's (tech with purge_only). One of `owner`, `admin`, `tech`, `readonly`. |
| `zone_id` | string (uuid) | No | Limits the token to that zone. |
| `expires_in_days` | integer | No | Default `90`. From 1 to 365. |
| `purge_only` | boolean | No | Token that can only purge its zone's cache (POST cache/purge and GET cache/purges; any other route, MCP included, answers 403 token_scope). Needs zone_id and no client; role tech (default). Default `false`. |
| `client_id` | string (uuid) | No | Limits the token to the zones of one client (roles tech and readonly only). A client-limited credential only issues tokens of its own client. |

#### Response

- `201`: Created; `secret` is shown only once. Returns [IssuedToken](https://developers.openwaf.dev/api/schemas/#issued-token).

| Field | Type | Description |
|---|---|---|
| `id` | string (uuid) | Id. |
| `org_id` | string (uuid) | Organization id. |
| `zone_id` | string (uuid) | Zone id. |
| `user_id` | string (uuid) | User id of the member. |
| `name` | string | Name. |
| `role` | string | Role. One of `owner`, `admin`, `tech`, `readonly`. |
| `prefix` | string | First characters of the secret, to recognise it. |
| `purge_only` | boolean | Can only purge its zone's cache. |
| `created_by` | string | Who created it (actor). |
| `created_at` | string (date-time) | Creation time. |
| `expires_at` | string (date-time) | Expiry time. |
| `last_used_at` | string (date-time) | Last use. |
| `client_id` | string (uuid) or null | Client the token is limited to (roles tech and readonly only); null = the whole organization. |
| `secret` | string | Shown only once; only its SHA-256 is stored. |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |

#### Example

**curl**


```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/tokens" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "name": "ci-deploy",
    "role": "tech",
    "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    "expires_in_days": 90
  }'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.createToken({
  body: {
    name: "ci-deploy",
    role: "tech",
    zone_id: "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
    expires_in_days: 90
  }
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.create_token(
    body={
        "name": "ci-deploy",
        "role": "tech",
        "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
        "expires_in_days": 90
    },
)
```



```json
{
  "id": "11111111-2222-4333-8444-555555555555",
  "org_id": "1e7c9a3b-5d2f-4b8a-9c6e-0f2a4b6c8d1e",
  "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
  "user_id": "5b8e2a1c-7d3f-4a9e-b6c2-1e4d7f0a3b9c",
  "name": "ci-deploy",
  "role": "tech",
  "prefix": "owf_8Jx2",
  "purge_only": false,
  "created_by": "user:5b8e2a1c-7d3f-4a9e-b6c2-1e4d7f0a3b9c",
  "created_at": "2026-10-27T09:30:00Z",
  "expires_at": "2027-01-25T09:30:00Z",
  "client_id": null,
  "secret": "owf_8Jx2…"
}
```

## Revoke token

```http
DELETE /v1/orgs/{org}/tokens/{id}
```

Revokes a token; it stops working at once.

**Required role:** `admin` or higher. Organization-wide, or any role to revoke the token making the request.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `id` | path | string (uuid) | Yes | Id of the resource. |

#### Response

- `204`: Revoked. No body.

#### Errors

| Status | Description |
|---|---|
| `404` | Not found, or not visible to the token (`not_found`). |

#### Example

**curl**


```sh
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/tokens/11111111-2222-4333-8444-555555555555" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.revokeToken({
  id: "11111111-2222-4333-8444-555555555555"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.revoke_token(id="11111111-2222-4333-8444-555555555555")
```
