# Authentication

Xantly uses Bearer tokens for all API requests. Two token types are supported.

---

## Token Types

| Type | Format | Use case |
| --- | --- | --- |
| **API Key** | `sk-...` | Server-to-server integrations, scripts, CI/CD. |
| **JWT** | `eyJ...` | Dashboard sessions, browser-based flows (auto-issued on login). |

Both types are passed identically:

```
Authorization: Bearer <token>
```

---

## Using Your API Key

### 1. Get a key

Create an API key from the [Xantly Dashboard](/dashboard/developer/keys) or via the Management API.

### 2. Store it securely

Set it as an environment variable. **Never commit API keys to source control.**

```bash
export XANTLY_API_KEY="sk-your-key-here"
```

### 3. Pass it in every request

Include the API key in the `Authorization: Bearer` header with every request.

```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["XANTLY_API_KEY"],
    base_url="https://api.xantly.com/v1",
)
```

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.XANTLY_API_KEY,
  baseURL: "https://api.xantly.com/v1",
});
```

```bash
curl -sS https://api.xantly.com/v1/chat/completions \
  -H "Authorization: Bearer $XANTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"auto","messages":[{"role":"user","content":"Hello"}]}'
```

---

## Authentication Errors

| HTTP | `error.code` | Meaning | Fix |
| --- | --- | --- | --- |
| `401` | `invalid_api_key` | Token is missing, malformed, or revoked. | Verify the `Authorization` header contains a valid `sk-...` key. |
| `401` | `expired_token` | JWT has expired. | Re-authenticate to obtain a fresh JWT. |
| `403` | `insufficient_permissions` | Key doesn't have the required scope. | Check key permissions in the dashboard. |

---

## Security Best Practices

1. **Environment variables only.** Store keys in `XANTLY_API_KEY`, never in source code or client bundles.
2. **Rotate regularly.** Create a new key, migrate, then revoke the old one.
3. **Least privilege.** Assign only the scopes each key actually needs.
4. **Monitor usage.** Use the dashboard to track per-key request volume and cost.
5. **Never expose in browsers.** API keys are server-side only. Browser apps should use JWT-based auth via your backend.

---

## Rate Limits

Rate limits are applied per API key and per organization. When exceeded, the API returns `429` with a `Retry-After` header.

```json
{
  "error": {
    "message": "Rate limit exceeded. Retry after 2 seconds.",
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded"
  }
}
```

Implement exponential backoff with jitter for production resilience.
