Skip to content

OAuth 2.1 for MCP clients

The deployment is a spec-compliant OAuth 2.1 protected resource, so MCP clients that speak the MCP authorization spec (claude.ai custom Connectors, MCP Inspector, …) can connect with no pre-shared token — just the endpoint URL (https://<host>/mcp). A signed-in human approves scoped access on a consent page.

The flow

  1. An unauthenticated POST /mcp returns 401 with WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource".
  2. That metadata (RFC 9728) names the api as the authorization server; its RFC 8414 metadata at /.well-known/oauth-authorization-server advertises the endpoints.
  3. The client registers itself (RFC 7591 dynamic client registration, POST /api/oauth/register), then sends the user to GET /api/oauth/authorize (PKCE S256 required). The RFC 8707 resource parameter is required and must equal the deployment's MCP resource URL (MCP_PUBLIC_URL, the same URL the protected-resource metadata advertises) — any other value is rejected with invalid_target.
  4. The user signs in (existing account) and approves the requested scopes on the consent page.
  5. The client exchanges the code at POST /api/oauth/token and calls /mcp with the resulting Bearer token. Refresh tokens rotate on every use; reusing a rotated refresh token revokes the whole grant (and its live access tokens).

What the tokens are

OAuth-issued access tokens are ordinary scoped tokens on the consenting human — same scopes, same per-token rate limits — short-lived (1 h) and silently renewed via refresh. Two OAuth-specific behaviors:

  • Audience-bound (RFC 8707). They are bound to the resource the grant named, so they are only accepted at that MCP endpoint. Hand-minted kbt_ tokens carry no audience and are unaffected.
  • Grant-scoped revocation. Revoking one (DELETE /api/tokens/:id) revokes the entire grant — refresh token included — so the client can't mint a replacement.

Scopes

The default grant is boards:read boards:write cards:read cards:write comments:write. A client may request a narrower/different set with the scope parameter. tokens:write can never be granted over OAuth — delegation chains stay rooted in an explicit human mint.

Configuration

  • MCP_PUBLIC_URL — the RFC 9728 resource identifier; grants are bound to it.
  • PUBLIC_BASE_URL — the public origin; base of the advertised metadata URLs.
  • OAUTH_ISSUER_URL — the issuer identifier (defaults to PUBLIC_BASE_URL).

See Configuration. For the non-OAuth transports (Bearer token, stdio proxy) see MCP.

Released under the AGPL-3.0 license.