==> read the decisions
ADR-0020: The API issues its own tokens; MCP clients register by metadata document, never dynamically
Status: Accepted (2026-10-15). Amends ADR-0005: the MCP door it deferred is specified here; personal access tokens stand. Partly implemented 2026-10-15: a new personal access token asks for a fresh sign-in; the authorization server (MCP, the docs' try-it) is not built yet.
Context
Section titled “Context”Three kinds of program call the API: scripts and tools with a personal access token (cs_pat_…,
ADR-0005), MCP clients (which the MCP specification requires to obtain OAuth 2.1 access tokens),
and the documentation host's "try it" calls (ADR-0022). Sign-in moves to an identity provider
(ADR-0019), so the question is which server issues the tokens these programs carry.
The MCP authorization specification (2026-07-28 revision) asks the authorization server for:
Client ID Metadata Documents (SHOULD) or pre-registered clients; dynamic client registration (RFC
7591) only as a deprecated fallback; PKCE; tokens bound to the MCP server named in the resource
parameter (RFC 8707), with the audience checked; protected resource metadata (RFC 9728) and server
metadata (RFC 8414). Of the Postgres-backed identity providers evaluated, none supports metadata
documents, and Authentik has no client registration of any kind.
Decision
Section titled “Decision”- Identity and authorization are separate. The identity provider answers "who is this"; the API is the authorization server for its own tokens and delegates every sign-in to the provider.
- Personal access tokens are unchanged: one kind, no scopes, issued, hashed, listed and revoked by the API. Creating one requires a fresh confirmation with a passkey or TOTP at the provider, so a token cannot be minted from a session that only ever saw a weaker factor.
- MCP clients obtain tokens from the API's OAuth endpoints:
- registration by Client ID Metadata Document or by pre-registration only. There is no dynamic client registration endpoint, now or later;
- authorization code with PKCE (S256 only), exact redirect-URI matching,
issin the response; - access tokens are short-lived, bound to the MCP server's URI from
resourceand checked for that audience; refresh tokens rotate on use; - the MCP server publishes protected resource metadata; the API publishes server metadata.
- The metadata fetch is hardened. Fetching a client's metadata document is a request the server
makes to a URL the client chose, from a host that can reach internal networks. It is limited to
https, to public addresses checked after resolution, with no redirects, a size limit and a timeout. - The consent screen shows where a client comes from: the metadata document's host, prominently, not only the name the document claims.
- The documentation host is a pre-registered client. Its "try it" obtains a short-lived token for
api.<domain>the same way, without a prompt when the visitor is signed in (ADR-0022). - A vetted OAuth server library implements the protocol; the platform writes the policy around it, not the protocol.
Consequences
Section titled “Consequences”- The identity provider can be chosen for sign-in alone; MCP does not constrain it.
- MCP clients that only support dynamic registration cannot connect. That is accepted: it is the deprecated path.
- The API owns a small, security-critical OAuth server: its tests cover the metadata fetch limits, redirect matching, PKCE, audience checks and refresh rotation.
- A later device flow for command-line tools fits the same endpoints.
Alternatives rejected
Section titled “Alternatives rejected”- The identity provider as the MCP authorization server. None of the candidates supports metadata
documents; one that offers open dynamic registration ignores
resource, so every registered client shares one audience. - Dynamic client registration. Deprecated by the specification, and an open endpoint anyone may call.
- Scoped personal access tokens. Kept simple on purpose: one kind of token, full reach, revocable.