Expand description
OAuth 2.0 Protected Resource Metadata for the MCP endpoints.
Implements RFC 9728 so MCP-aware clients (e.g. Claude Desktop’s Custom Connectors, ChatGPT remote MCP) can discover the authorization server they need to authenticate against in order to call our MCP endpoints.
The discovery document is published at
/.well-known/oauth-protected-resource and is public (no auth).
Clients reach it either by following the resource_metadata parameter
emitted in a WWW-Authenticate challenge from a 401 on /api/mcp/*
(see crate::http::AuthError), or by probing the well-known URI
directly.
§Host derivation
The resource field and the resource_metadata URL embedded in the
401 challenge are both absolute URLs and therefore depend on knowing
the externally-visible host of this environment. We resolve that in
this order:
HttpConfig::http_host_name(set by the operator).- The request’s
Hostheader.
We deliberately do not consult X-Forwarded-Host or
X-Forwarded-Proto: environmentd has no proxy-trust configuration
today, and trusting those headers blind would let any client reaching
the server directly poison the published metadata URLs (a host-header
injection on the OAuth flow). Deployments behind a load balancer that
rewrites Host are expected to set http_host_name explicitly.
§When the document is published
The handler returns 404 when no OAuth flow is meaningful for the
listener: either because oidc_issuer is unset (no authorization
server to advertise) or because the listener’s authenticator is
listeners::AuthenticatorKind::None (no token would ever be
validated). Returning an empty or fake document instead would mislead
clients into starting an OAuth dance they cannot complete.
Structs§
- McpO
Auth 🔒Config - Per-listener config shared by the OAuth discovery handler and the auth
middleware’s
WWW-Authenticatebuilder. Carried as an axumExtensionbecause one environmentd process can serve listeners with different authenticators andhttp_host_names. - Oauth
Metadata Metrics - Prometheus counter for the discovery endpoint, labeled by the
MetricStatusof each request so dashboards key off names rather than HTTP status codes. - Protected
Resource 🔒Metadata - JSON shape returned by
PROTECTED_RESOURCE_METADATA_PATH. A strict subset of RFC 9728 §2; further fields can be added without breaking clients per the RFC’s extensibility guidance.
Enums§
- McpO
Auth 🔒Discovery - Whether and how an HTTP listener advertises OAuth 2.0 for its MCP
routes. Derived once per listener from its authenticator and consulted
by both the 401
WWW-Authenticatechallenge and this discovery handler, so the two never disagree about whether OAuth is on offer. - Metric
Status 🔒 - Closed set of outcomes recorded by
OauthMetadataMetrics. Keeping these as an enum (rather than free-form strings at the call sites) pins the metric’s label cardinality and stops typos from silently creating new label values.
Constants§
- ADAPTER_
WAIT_ 🔒TIMEOUT - Bounds how long the unauthenticated discovery handler waits for the adapter client. Without this, a wedged adapter could pin connections indefinitely from any caller on the network.
- MCP_
SCOPE 🔒 - OAuth scope advertised for the MCP endpoints. Not enforced server-side (authorization is at the SQL layer via RBAC).
- METADATA_
CACHE_ 🔒CONTROL private(not the RFC-defaultpublic): the document varies by host, so shared caches must not serve one listener’s document to another.- PROTECTED_
RESOURCE_ 🔒METADATA_ PATH - The well-known path served by this module.
- PROTECTED_
RESOURCE_ 🔒METADATA_ PATH_ AGENT - Path-suffixed aliases of
PROTECTED_RESOURCE_METADATA_PATHper RFC 9728 §3.1. Both MCP endpoints serve an identical metadata document today, so the same handler is mounted at all three paths; the aliases exist so strict clients that always probe with a path suffix do not have to fall back to the bare URI. - PROTECTED_
RESOURCE_ 🔒METADATA_ PATH_ DEVELOPER - PUBLISHED_
SCHEME 🔒 - OAuth 2.1 §3.1 requires
httpsfor all OAuth endpoints.
Functions§
- handle_
protected_ 🔒resource_ metadata - HTTP handler for
PROTECTED_RESOURCE_METADATA_PATH. - metadata_
url 🔒 - Builds the absolute URL of the protected resource metadata document
for use as the
resource_metadataparameter in aWWW-Authenticatechallenge. ReturnsNoneif the request lacks enough host information to construct a URL; the caller is expected to skip the Bearer challenge in that case rather than emit a malformed value. - resolve_
host 🔒 - Resolves the host string to embed in published absolute URLs.
- validate_
issuer_ 🔒url - Validates
oidc_issuerbefore it is published. Required: parses as a URL, scheme ishttpsorhttp, no userinfo (we publish it on a public endpoint), no query or fragment (RFC 8414 §2). Thehttpscheme is permitted to ease local dev; OAuth 2.1 §3.1 forbids it in production but enforcement is the operator’s responsibility.