<!-- Agent Datasets docs · Authentication · canonical: https://www.agentdatasets.com/docs/authentication · rendered from https://www.agentdatasets.com -->

# Authentication

One credential covers both surfaces: an API key, sent as a header. The hosted MCP endpoint and the REST API check it the same way, in middleware, before a request reaches any tool.

## Where keys come from

Create, rotate, and revoke keys in the [dashboard](/dashboard/keys). A key is shown in full exactly once, at creation; after that the dashboard only ever shows its prefix. Rotation mints a replacement under the same prefix and revokes the old secret in one step, so a compromised key is a two-minute fix rather than a re-onboarding.

Keys minted in the dashboard belong to the signed-in account and run on the **public surface**. That matters for more than billing: the public surface is where the redistribution gate applies, so a public key can only ever receive data that is licensed for redistribution. Provider-licensed data is absent from the public surface entirely — not thinned, not masked, absent — which is why the tool catalog and the REST reference are generated from what a public key can actually see.

## Sending the key

Both surfaces read the same header:

```http
X-API-KEY: adk_...
```

For MCP clients the header goes in the server config — the [Quickstart](/docs/quickstart) has the block for each client. A request with no key, an unknown key, or a revoked key is rejected by the middleware before dispatch:

```json
{ "error": { "code": "unauthorized", "message": "missing or invalid API key" } }
```

Over REST the header goes on every request. A complete authenticated call, taken from the published specification:

## Limits a key carries

Two limits apply, and they are different things:

- A **per-key request rate**, measured in a short sliding window. The dashboard shows each key's limit and its current-window usage side by side, so you can see a client approaching it before it trips. Exceeding it returns `rate_limited`.
- A **per-account monthly quota** across every key the account owns. Exceeding it returns `quota_exceeded`, and the error carries the instant the window resets.

Both codes are in the [error reference](/docs/errors) with their HTTP statuses and their MCP rendering. Neither is the same as `upstream_rate_limited`, which means a data provider throttled one of our connectors rather than us throttling you.

## OAuth discovery

The hosted MCP endpoint advertises OAuth 2.1 protected-resource metadata at `/.well-known/oauth-protected-resource`, and an unauthenticated request comes back with a `WWW-Authenticate` challenge pointing at it — so a client that speaks OAuth discovery will find the authorization server. Self-serve OAuth onboarding is not open yet, though. Until it is, use an API key from the dashboard; that is the supported path for both surfaces.

## Keeping keys out of trouble

- A key is a bearer credential: anything holding it can spend your quota. Keep it out of source control, out of client-side bundles, and out of anything a browser can read.
- Give each client its own key. Per-key usage is visible in the dashboard, so a noisy or leaked integration can be identified and revoked without disturbing the others.
- Revoke rather than delete-and-forget. A revoked key fails closed immediately on both surfaces.
