> ## Documentation Index
> Fetch the complete documentation index at: https://unif.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> API keys, scoping, environments and key hygiene.

Unif uses bearer tokens. There is no OAuth flow, no request signing and no session to maintain.

```bash theme={null}
curl https://api.unif.dev/v1/me \
  -H "Authorization: Bearer unif_sk_live_8f3c1a9e4b2d8065f1a3c7e9b5d2408f"
```

A missing, malformed or revoked key returns `401` with an `authentication_error`. Unif never
falls back to an anonymous mode.

## Key format

| Prefix          | Environment | Behavior                                                          |
| --------------- | ----------- | ----------------------------------------------------------------- |
| `unif_sk_live_` | Live        | Queries real data and consumes credits.                           |
| `unif_sk_test_` | Sandbox     | Returns [fixture data](/docs/platform/sandbox), consumes nothing. |

The prefix is deliberately greppable. Secret scanners can match `unif_sk_` and catch a key before
it reaches a public repository.

## Scope

A key is bound to exactly one workspace. It cannot read another workspace's lists, jobs or
trackers, and `404` — not `403` — is what you get for an object outside your workspace, so key
probing reveals nothing about what exists.

Within a workspace, every key carries the same permissions. Separate keys per service give you
independent revocation and a clean read of the [usage ledger](/docs/platform/credits#the-ledger),
not narrower access.

<Tip>
  Issue one key per deployed service — `api-prod`, `etl-nightly`, `analytics-notebook`. When one
  leaks you roll one key, and the ledger tells you which service spent what.
</Tip>

## Storing keys

<Steps>
  <Step title="Keep them out of source control">
    Use environment variables or a secret manager. Never a config file that ships, and never the
    client side — a key in a browser or mobile binary is a public key.
  </Step>

  <Step title="Proxy browser traffic">
    If a frontend needs Unif data, call Unif from your own backend and forward the result. The
    API sets no CORS headers for a reason.
  </Step>

  <Step title="Rotate on a schedule">
    Create the new key, deploy it, confirm traffic has moved on the ledger, then revoke the old
    one. Both keys work during the overlap, so rotation needs no downtime.
  </Step>
</Steps>

## Verifying a key programmatically

`GET /v1/me` is cheap, free of credit cost and safe to call on boot as a health check.

```python theme={null}
import os, requests

def check_unif_key() -> dict:
    resp = requests.get(
        "https://api.unif.dev/v1/me",
        headers={"Authorization": f"Bearer {os.environ['UNIF_API_KEY']}"},
        timeout=10,
    )
    if resp.status_code == 401:
        raise RuntimeError("UNIF_API_KEY is missing, malformed or revoked")
    resp.raise_for_status()
    return resp.json()
```

The response tells you the environment and the entitled channels, which makes it a useful guard
against the classic mistake of pointing a staging deployment at a live key.

## Revocation

Revoking a key from the dashboard takes effect within seconds. In-flight requests complete;
everything after fails with `401`. Revocation is not reversible — issue a new key instead.

<Warning>
  If you believe a key has leaked, revoke first and investigate second. Check
  [`GET /v1/usage/events`](/api-reference/usage/list-usage-events) afterwards for calls you cannot
  account for.
</Warning>
