# doc0 agent authentication

Last updated 2026-09-01. Canonical: https://www.doc0.app/auth.md.

> doc0's API is its MCP server, one per project at `https://www.doc0.app/api/mcp/<projectId>/mcp` (Streamable HTTP; `/sse` for the SSE transport). A public wiki needs no credential at all. A private one takes a Bearer key or an OAuth 2.1 access token. This page is the agent_auth walkthrough; the machine-readable form is the RFC 9728 protected resource metadata.

## Discover

- Protected resource metadata (RFC 9728): https://www.doc0.app/.well-known/oauth-protected-resource. It names the authorization server, the supported scopes (`mcp:read` and `mcp:graph`) and the bearer method (`Authorization` header). The path-aware form `https://www.doc0.app/.well-known/oauth-protected-resource/api/mcp/<projectId>/mcp` serves the same document.
- Authorization server metadata (RFC 8414) is published by the authorization server the PRM names; clients derive its URL from the issuer.
- Server card: https://www.doc0.app/.well-known/mcp.json. Site index: https://www.doc0.app/llms.txt.
- A request without a usable credential on a private project answers `401` with `WWW-Authenticate: Bearer resource_metadata="<PRM URL>"`, so one call tells an agent where to look.

## Pick a method

1. **No credential.** Any project whose docs mode is public AND exposed over MCP (`technical_is_public` with `technical_mcp_enabled`, or the `user_guide_*` pair; a public wiki whose owner switched MCP off answers `404`) answers the documentation tools without a token: `doc0_get_minimal_context`, `doc0_list_pages`, `doc0_get_page`, `doc0_search_docs`. The code-graph tools (`doc0_query_graph`, `doc0_symbol_context`, `doc0_impact_analysis` and the rest of the `mcp:graph` set) additionally need the project's graph access switched on for the public (`graph_tools_public`, off by default) or one of the credentials below. Try this first.
2. **Project key** (`doc0_proj_*`). Scoped to one project. The recommended credential for CI, scripts and a coding agent working on one repository.
3. **Personal key** (`doc0_mcp_*`). Unlocks the projects the keyholder OWNS, and only those: a team member on someone else's project gets `401` with it and needs that project's key instead. For an owner's own tooling.
4. **OAuth 2.1** (`identity_assertion`, the signed-in user's identity). For MCP clients with a browser: Claude Desktop, Cursor, mcp-inspector and similar. Scopes are granted per client, so this is the least-privilege option.

Bearer keys unlock every enabled tool of the project; OAuth tokens are limited to the scopes they carry.

## Register

- Keys are minted by a person in the doc0 dashboard: a project key on the project's Overview tab, a personal key under Settings, then Integrations. There is no register_uri for keys; an agent asks its user for one.
- OAuth clients register themselves: the authorization server supports **dynamic client registration** (RFC 7591) as the MCP authorization spec requires. Fetch the PRM, derive the AS metadata, POST to its `registration_endpoint`, then run the authorization-code flow with PKCE. Request `mcp:read` for the documentation tools, `mcp:graph` for the code-graph tools (`mcp:graph` implies `mcp:read`).

## Claim

- Keys are shown once at creation; store them as a secret. No claim step.
- The OAuth flow ends at doc0's consent page, where the signed-in user approves the client and the requested scopes; the authorization code is then exchanged for an access token at the AS token endpoint.

## Use the credential

- Send `Authorization: Bearer <key or access token>` on every MCP request.
- Call `doc0_get_minimal_context` first (it accepts an optional `task`), then `doc0_search_docs` or `doc0_list_pages`, then `doc0_get_page`. Tool calls are metered per minute per IP; every response carries `response_chars` and `next_tool_suggestions`.
- `npx doc0 setup` writes the MCP entry and an always-on rule into Claude Code, Cursor or Codex for a repository; `npx doc0 remove` undoes it.

## Errors

- `401` with `WWW-Authenticate: Bearer realm="mcp", resource_metadata="…"`: no credential, or a key that does not exist. Fetch the PRM and pick a method above.
- `401 invalid_token`: the OAuth token is expired, or its audience is not this server. Refresh or re-authorize.
- `403 insufficient_scope` with `scope="<required>"`: the OAuth grant lacks the tool's scope. Re-authorize requesting the named scope (step-up authorization).
- `429` with `Retry-After`: the per-minute cost budget is spent; wait and retry.
- `503`: the authorization server's keys could not be fetched. Retry later; this is not a credential problem.

## Revocation

- Keys are revoked by their owner in the dashboard (rotate a project key on the Overview tab; delete a personal key under Settings). Successful key verifications are cached in each server instance for 60 seconds, so a revoked key can keep answering for up to a minute before it answers `401`; treat revocation as taking effect within a minute, not instantly.
- OAuth grants are revoked at the authorization server; doc0 does not expose a revocation_uri of its own.

## Sitemap

See the full [sitemap](https://www.doc0.app/llms.txt) for all pages, and [the site as markdown](https://www.doc0.app/index.md).
