# Access Tokens

Authorize epilot API calls with Access Tokens: create, restrict (read-only or anonymized), use and revoke tokens for integrations and scripts.

[[API Docs](/api/access-token)]
[[SDK](https://www.npmjs.com/package/@epilot/sdk)]

> **Info: To call epilot APIs, requests must be authorized using a valid _Access Token_.**

## Using Access Tokens

Pass the access token in the `Authorization` request header:

```http title="Authorization header"
Authorization: Bearer <your-access-token>
```

## Creating Access Tokens

Manage Access Tokens from [Settings > Access Tokens](https://portal.epilot.cloud/app/tokens) in the epilot 360 app. Creating tokens requires the `token:create` permission.

By default, a new Access Token inherits the roles and permissions of the creating user.

When creating a token, you can optionally set an **expiry**. A token with an expiry is automatically invalidated once it passes; a token created without one remains valid until revoked. Setting an expiry is recommended to limit the impact of a leaked token.

![Access Token create view](/img/create-access-token.png)

> **Note: The generated token is shown only once and must be saved by the user.**

## Restricting Access Tokens

Two options restrict what a token can do, independently of its roles. Both are set when the token is created, are enforced server-side, and can't be switched off by the token holder.

### Read-only tokens 

A token created with **Read-only** (`read_only: true`) can perform read actions only. Every write action is denied, regardless of the token's roles.

### Anonymized tokens 

A token created with **Anonymize** (`anonymize: true`) receives PII-anonymized entity data: names, emails, phone numbers, addresses, IBANs, and other personal data are replaced with pseudonyms in every Entity API response. Entity exports are blocked for anonymized tokens.

> **Caution: Anonymization is best effort**
Standard fields are masked automatically, but custom attributes are only masked when they are recognized as personal data or marked **Anonymize** in the entity schema. Read [PII Anonymization](/docs/auth/anonymization) to learn what is covered and how to classify your attributes before you hand an anonymized token to an AI assistant or a third party.

Combine both options for AI assistants and analytics integrations: an anonymized token can't write pseudonyms back over your real data if it is also read-only.

## Revoking Access Tokens

Delete an Access Token from the management view to revoke it. After revocation, the token is immediately invalidated.

![Access Token management view](../../static/img/access-token-management.png)

> **Caution: epilot doesn't store and cannot recover lost or revoked access tokens.**

## Access Token API

Generate access tokens programmatically using the [Access Token API](/api/access-token) `createAccessToken` operation:

```http title="Create a basic token"
POST /v1/access-tokens
```

```json title="Request body"
{
  "name": "Token for my application"
}
```

Optionally, pass a list of Role IDs to scope the token to specific roles. By default, the token inherits the caller's roles.

```http title="Create a scoped token"
POST /v1/access-tokens
```

```json title="Request body with role assignment"
{
  "name": "Postman Access Token",
  "assume_roles": ["123:owner"]
}
```

Set an optional expiry with the `expires_in` parameter — a number of seconds (e.g. `3600`) or a duration string with time units (e.g. `'10h'`, `'7d'`, `'2 days'`), bounded between 30 seconds and 365 days. Without `expires_in`, the token does not expire.

```json title="Request body with expiry"
{
  "name": "Postman Access Token",
  "assume_roles": ["123:owner"],
  "expires_in": "30d"
}
```

Set `read_only: true` or `anonymize: true` to create a [restricted token](#restricting-access-tokens):

```json title="Request body for a read-only, anonymized token"
{
  "name": "AI analytics",
  "read_only": true,
  "anonymize": true,
  "expires_in": "7d"
}
```

A token created by an anonymized token is always anonymized too, whatever the request body says.

Tokens created with `expires_in` are stored, listed, and revocable exactly like non-expiring tokens. The response includes an `expires_at` timestamp, and the token stops working — and drops out of the token list — once it expires:

```json title="201 response for a token with expiry"
{
  "id": "api_5ZugdRXasLfWBypHi93Fk",
  "created_at": "2019-08-24T14:15:22Z",
  "expires_at": "2019-09-23T14:15:22.000Z",
  "name": "Postman Access Token",
  "assignments": ["123:owner"]
}
```

Each Access Token generated via the API receives a unique ID.

```json title="201 response"
{
  "id": "api_5ZugdRXasLfWBypHi93Fk",
  "created_at": "2019-08-24T14:15:22Z",
  "name": "Postman Access Token",
  "assignments": ["123:owner"]
}
```

Revoke access tokens using the `revokeAccessToken` operation:

```http title="Revoke an access token"
DELETE /v1/access-tokens/api_5ZugdRXasLfWBypHi93Fk
```

```json title="200 response"
{
  "id": "api_5ZugdRXasLfWBypHi93Fk",
  "created_at": "2019-08-24T14:15:22Z",
  "name": "Postman Access Token",
  "assignments": ["123:owner"]
}
```

## See Also

- [Token Types](/docs/auth/token-types) — comparison of all epilot token types
- [PII Anonymization](/docs/auth/anonymization) — how anonymized tokens mask personal data
- [Authentication](/docs/auth/authentication) — OAuth 2.0 login flow
- [Permissions](/docs/auth/permissions) — role-based access control and grants