# Authentication

## Send the token

Every request carries the token as a bearer token:

```bash
curl -H "Authorization: Bearer mf_YOUR_TOKEN" https://YOUR-MYFORGE/api/v1/token
```

The only public endpoint is `GET /api/v1/openapi.json` (the API description).

## What a token is

- A token belongs to one person and one team. It acts as that person, in that team, and never has more rights than that person has right now.
- pfcloud stores only a fingerprint of the token. If you lose it, use **New secret** (same settings, new value) or make a new token.
- Tokens are made and revoked in the dashboard under **API**, then **Tokens**. The API cannot make tokens.

## Settings you choose when you make a token

| Setting | What it does | Advice |
| --- | --- | --- |
| Scopes | The rights the token has. See [Scopes and permissions](/developers/scopes-and-permissions). | Tick only what the job needs. |
| Expiry | Required. After this time the token answers `401`. The team owner can set a maximum (1 to 365 days). | Days for AI tools, weeks for CI. |
| Allowed addresses | IP addresses or CIDR ranges (for example `203.0.113.7` or `203.0.113.0/24`). From any other address the token answers `403`. | Use it whenever the caller has a fixed address. The team owner can make it required. |
| Limits | Only some servers and sites. A server includes all its sites. Anything outside the limit answers `404`, as if it did not exist. | Give an AI only the servers it needs. A token with limits cannot add servers. |

## Check a token: GET /token

```bash
curl -s -H "Authorization: Bearer $TOKEN" https://YOUR-MYFORGE/api/v1/token
```

The `data` object contains:

| Field | Meaning |
| --- | --- |
| `id`, `name` | The token's public id and its name. |
| `team` | `name` and `slug`. |
| `acts_as` | The person (`name`, `role`) the token acts as. |
| `scopes` | Scopes the token has. |
| `usable_scopes` | Scopes that pass every check right now. |
| `blocked_scopes` | A map of scope to the reason it is blocked (plan, owner rule, or missing permission). Empty when nothing is blocked. |
| `limited_to` | The server and site limits, or null. |
| `allowed_ips` | The address list, or null. |
| `expires_at` | When it expires. |
| `requests_count` | How many calls it has made. |

Call this at the start of every integration and every AI session.

## What the errors mean

| Status | Message (shortened) | Meaning |
| --- | --- | --- |
| `401` | Missing, wrong or expired API token | The header is missing or wrong, the token expired or was revoked. |
| `401` | The person who made this token is no longer in the team | The token is dead. Make a new one. |
| `403` | This token can't be used from `<ip>` | The address is not in `allowed_ips`. |
| `403` | The person who made this token must turn on two-factor authentication first | The team requires two-factor sign-in for its members. |
| `403` | This token doesn't have the `<scope>` scope | Add the scope (make a new token). |
| `403` | The team's plan doesn't include `<scope>` | Plan limit. Ask the team owner or support. |
| `403` | The team owner switched `<scope>` off for API tokens | Owner rule under **API**, then **Rules**. |
| `403` | The token's maker no longer has the permission "..." | The person's role changed. A token cannot outgrow its maker. |

A token loses a right the moment the plan, the owner or the maker's role takes it away. Nothing needs to be changed on the token.

## Good habits

- Store tokens in a secret manager or CI secret, never in code or chat. See [AI security](/developers/ai-security).
- One token per system, so you can revoke one without breaking others.
- Look at **API**, then **Activity** from time to time: the last 100 calls with token, call, answer and address.
