# Auth

Every request needs an `X-API-Key` header. Keys are scoped, so a key created for read-only access can't create or delete resources even if it leaks.

## Setting the header

```js title="client.js"
const res = await fetch("https://api.kitchen-sink.example.com/v1/widgets", {
  headers: { "X-API-Key": process.env.ACME_API_KEY },
});
```

## Line highlighting - `{1,3-4}` meta

```js {1,3-4}
const key = process.env.ACME_API_KEY;
const url = "https://api.kitchen-sink.example.com/v1/widgets";
const headers = { "X-API-Key": key };
const res = await fetch(url, { headers });
console.log(await res.json());
```

## Line highlighting - `[!code highlight]`

```js
function authenticate(request) {
  const key = request.headers.get("X-API-Key"); // [!code highlight]
  if (!key) throw new Error("Missing API key");
  return lookupKey(key);
}
```

## Word highlighting - `/word/` meta

```js /apiKey/
const apiKey = process.env.ACME_API_KEY;
fetch(url, { headers: { "X-Api-Key": apiKey } });
```

## Word highlighting - `[!code word:...]`

```js
const scope = "widgets:read"; // [!code word:read]
```

## Focus

```js
function setup() {
  loadConfig();
  authenticate(); // [!code focus]
  connectToDatabase();
}
```

## Diff

```js
const key = "sk_test_hardcoded"; // [!code --]
const key = process.env.ACME_API_KEY; // [!code ++]
```

## Error / warning

```js
const safe = validateApiKey(key);
const unsafe = eval(key); // [!code error]
const deprecated = legacyAuth(key); // [!code warning]
```

## Wrap

```js wrap
const errorMessage = "The provided API key is either missing, malformed, or has been revoked - check the dashboard under Settings → API Keys to confirm it's still active before retrying.";
```

## Line numbers

```js lines
function isExpired(token) {
  return Date.now() > token.expiresAt;
}
console.log(isExpired(currentToken));
```

## Expandable

```python expandable
class ApiKey:
    def is_valid(self): pass
    def scopes(self): pass
    def rotate(self): pass
    def revoke(self): pass
    def last_used_at(self): pass
    def created_by(self): pass
    def expires_at(self): pass
    def rate_limit_tier(self): pass
```

<Callout type="warning">
  Keys don't expire by default, but you can set an expiry when creating one. An expired key returns `401 Unauthorized` with `{ "error": "token_expired" }` - the same shape as a missing or revoked key, so don't rely on the error message alone to distinguish the two.
</Callout>