# Authentication

> Authenticate Mortar API requests with an API key. How keys are created, scoped, stored as hashes, shown once, given an expiry, rotated without downtime and revoked, and why a revoked or expired key can work for up to 30 seconds.

Every inference request carries an API key in the `Authorization` header. Keys belong to an organization, are created in the console and are shown exactly once.

## Send your key

Pass the key as a bearer token. Mortar reads no other header and never accepts a key in the URL.

```bash title="Request"
curl https://api.mortar.one/v1/models \
  -H "Authorization: Bearer $MORTAR_API_KEY"
```

The OpenAI SDKs send this header for you from the `api_key` (Python) or `apiKey` (TypeScript) option. A few endpoints need no key at all; the [API reference](/docs/api#authentication) marks each one.

## API keys

A Mortar key looks like `mk_live_` followed by 32 random URL-safe characters.

- **Shown once.** The console displays the full key when you create it and never again. If you lose it, create a new key and revoke the old one.
- **Stored as a hash.** Mortar keeps a SHA-256 hash of the key, not the key itself. A copy of Mortar's database can't be replayed against the API.
- **Recognisable by prefix.** The first 12 characters, such as `mk_live_Q3vZ`, are stored in the clear so you can tell keys apart in the console. They're far too short to use as a key.
- **Organization-wide.** A key acts for the organization it was created in, not for the person who created it. Mortar still records who created it: removing that person from the organization revokes every key they created that still works, and the console lists those keys before you confirm.

## Create a key

1. Sign in and open [API keys](/settings/keys) in your settings.
2. Create a key and give it a name of up to 64 characters that says where it's used, such as `billing-service-prod`. A key with no name is called "Untitled key".
3. Choose when it expires: in 7, 30 or 90 days, in 1 year, or never. The console picks 30 days unless you choose otherwise.
4. Copy the key into your secret manager or deployment environment straight away.

Creating, listing, rotating and revoking keys needs the **Admin** or **Owner** role.

> [!WARNING]
> Treat a key like a password. Don't commit it, log it or ship it in browser or mobile code: anyone holding it can send requests that your organization pays for.

## Scopes

Every key carries two scopes, `inference:read` and `inference:write`, which together cover every authenticated endpoint. Narrower keys can't be issued yet, so give each service its own key: revoking one then never interrupts another.

## Key expiry

A key that expires is refused from then on with `invalid_api_key`, exactly like a revoked one. The API keys page shows when each key expires and flags a key that expires within 7 days, so you can rotate it first. A key you chose not to expire works until it is revoked: rotate those on a schedule of your own.

## Rotate a key

Rotation needs no downtime, because the old and new keys work side by side for a window you choose.

1. Open [API keys](/settings/keys) and choose **Rotate** on the key.
2. Choose how long the old key keeps working: 1 hour, 24 hours, 7 days, or stop it now. Mortar creates a replacement with the same name and the same lifetime, and shows it once.
3. Deploy the new key everywhere the old key is used.
4. Check that the old key's **Last used** time has stopped advancing. The old key stops working when its window ends, or straight away if you chose to stop it now.

A window never extends a key: an old key that was due to expire sooner stops at its own expiry. A key can be rotated once; after that, rotate its replacement. You can also rotate by hand: create a key, deploy it, then revoke the old one.

## Revoke a key

Open [API keys](/settings/keys) and revoke the key. Revoking is permanent: a revoked key can't be restored, only replaced.

> [!CAUTION]
> A revoked or expired key can keep working for up to 30 seconds. Each data-plane replica caches a successful key check for 30 seconds so that requests don't wait on the control plane, and a replica that checked the key just before you revoked it, or just before it expired, accepts it until that entry expires. Allow for this window when you respond to a leaked key.

## Authentication errors

Failed authentication returns the standard [error envelope](/docs/api#errors) with `type` set to `authentication_error` and a `WWW-Authenticate: Bearer realm="mortar"` header.

| Status | Code | What happened | What to do |
| --- | --- | --- | --- |
| 401 | `missing_api_key` | The request had no `Authorization: Bearer` header. | Send your key as a bearer token. |
| 401 | `invalid_api_key` | The key is unknown, mistyped, revoked or expired. | Check the key, or create a new one. |
| 503 | `verifier_unavailable` | Mortar couldn't reach the service that checks keys. | Retry with backoff. The request was not processed. |

```bash title="A request without a key" status=401
curl https://api.mortar.one/v1/models
```

```json title="Response" output
{
  "error": {
    "message": "Missing API key. Pass it as an Authorization header: \"Authorization: Bearer MORTAR_API_KEY\".",
    "type": "authentication_error",
    "code": "missing_api_key"
  }
}
```

## Console sessions

The Mortar console calls the same endpoints with your browser session instead of a key. Mortar accepts a session only when a request carries no key and comes from the console's own site. Use API keys for everything you build.
