RFC compliance
TL;DR — AuthPlane implements the subset of each RFC needed for MCP authorization: not less, not more. Every deviation is opt-in, documented, and tied to an ADR. Legacy grants (implicit, ROPC) are intentionally omitted per OAuth 2.1 security guidance. This page is the compliance statement — one row per RFC with what’s covered, what’s not, and why.
Design philosophy
Every RFC below is implemented to the letter unless the “Deviation” column says otherwise. Where an RFC offers multiple approaches (token formats, client auth methods), AuthPlane picks the secure-by-default option. The full test matrix — one test per RFC section — is in authserver/wiki/COMPLIANCE_TEST_MATRIX.md.
Core OAuth
RFC 6749 — OAuth 2.0 Authorization Framework
Implemented sections: §4.1 (Authorization Code Grant), §4.4 (Client Credentials), §3.3 (Scope), §5.2 (Error responses).
Coverage:
- Authorization Code grant with mandatory PKCE (RFC 7636)
- Client Credentials grant (RFC 6749 §4.4) — see below
- Scope validation against registered scopes
- Client authentication:
none,client_secret_basic,client_secret_post - Error responses per §5.2
Configurable default-scope handling (ADR-012): when oauth.require_scope: false, missing scope in authorize requests defaults to the resource’s registered scopes. RFC 6749 §3.3 explicitly allows this: “If the client omits the scope parameter … the authorization server MUST either process the request using a pre-defined default value or fail the request indicating an invalid scope.” We ship the fail branch by default (spec-strict); the toggle switches on the pre-defined default branch that the RFC also permits.
Not implemented: Implicit grant (§4.2), Resource Owner Password Credentials (§4.3) — OAuth 2.1 removes both from the spec.
RFC 6749 §4.4 — Client Credentials
Machine-to-machine token issuance. Requires client_secret_post or client_secret_basic. Supports scope validation and resource audience binding.
Configuration: client_credentials.enabled: true (disabled by default). Only confidential clients with client_credentials in their grant_types.
Token format: RFC 9068 JWT with typ: at+jwt, sub = client_id (no user), aud bound to resource when set. Introspection + revocation supported.
RFC 7636 — PKCE
S256 only. plain method rejected. Missing code_challenge rejected.
RFC 9700 — OAuth 2.0 Security BCP
Coverage: PKCE required, exact redirect-URI matching, refresh-token rotation with reuse detection, no implicit grant, DPoP available.
Token format
RFC 9068 — JWT Profile for OAuth 2.0 Access Tokens
Access tokens are JWTs with typ: at+jwt, standard claims (iss, sub, aud, exp, iat, jti, client_id, scope).
RFC 7517 — JSON Web Key (JWK)
JWKS endpoint at /.well-known/jwks.json. Supports ES256 (EC P-256) and RS256 key types.
Discovery
RFC 8414 — OAuth 2.0 Authorization Server Metadata
Full AS metadata at /.well-known/oauth-authorization-server. Fields returned:
issuer,authorization_endpoint,token_endpoint,registration_endpoint,revocation_endpointintrospection_endpoint(whenintrospectionenabled)jwks_uriresponse_types_supported,grant_types_supported,token_endpoint_auth_methods_supportedcode_challenge_methods_supported: ["S256"]scopes_supported(aggregated from all resources’ scopes)resource_indicators_supported: truedpop_signing_alg_values_supported(when DPoP enabled)authplane_agent_identity_supported: true(AuthPlane extension)
RFC 9728 — OAuth 2.0 Protected Resource Metadata
Served by the resource server (i.e., your MCP server via the SDK) at /.well-known/oauth-protected-resource. MCP clients use this to discover the authorization server. AuthPlane’s SDKs generate and serve this automatically.
Client registration
RFC 7591 — Dynamic Client Registration
Three modes:
open— anyone can register (dev only)approved_redirects— anyone can register, redirect URI must matchdcr.approved_redirectspatternsadmin_only— pre-registration required via Admin API/CLI
Fields supported: redirect_uris, client_name, token_endpoint_auth_method, grant_types, scope, and AuthPlane extensions for agent identity.
draft-ietf-oauth-client-id-metadata-document — CIMD
When client_id is a URL, AuthPlane fetches the metadata document at that URL, validates fields, and uses it for registration. Configurable via cimd.require_https (default true), cimd.cache_ttl, cimd.fetch_timeout.
Resource indicators
RFC 8707 — Resource Indicators for OAuth 2.0
The resource parameter in /oauth/authorize and /oauth/token binds tokens to a specific resource server via the aud claim.
Strict exact-string matching — trailing slashes matter. See Configuration: Resources for the URI-mismatch trap.
Token lifecycle
RFC 7009 — Token Revocation
Revocation endpoint at /oauth/revoke. Accepts both access tokens and refresh tokens. Returns 200 on success and for invalid/unknown tokens per §2.2; error responses (unsupported_token_type, client-auth failure, 503) follow §2.2.1.
RFC 7662 — Token Introspection
Introspection endpoint at /oauth/introspect. Accepts access tokens and machine tokens. Requires client authentication (client_secret_post or client_secret_basic) for confidential clients.
Refresh token rotation
Refresh tokens rotate on every use — a new token is issued, the old one consumed. Reuse detection — a second use of a consumed refresh token revokes the entire token family (RFC 9700 §4.14).
Error format
RFC 9457 — Problem Details for HTTP APIs
Error responses include both OAuth error fields (error, error_description) and Problem Details fields (type, title, detail, status). Content-Type: application/problem+json.
Full error catalog in Reference: Errors.
Proof of possession
RFC 9449 — OAuth 2.0 Demonstrating Proof of Possession (DPoP)
Full support including proof validation, token binding, and server nonces.
Coverage:
- DPoP proof JWT validation (§4.3):
typ,alg,jwk,htm,htu,iat,jti,nonce - Supported algorithms:
ES256,RS256,PS256 - Algorithm restriction:
alg:noneand all symmetric algorithms rejected - Private key in
jwkheader rejected htucomparison strips query string (scheme + authority + path; authority includes non-default port; compared after RFC 3986 normalization)- JKT computation per RFC 7638 (JWK Thumbprint) — base64url-encoded SHA-256
- Token binding via
cnf.jktclaim in access tokens - DPoP-bound token type:
token_type: DPoP - Server-issued nonces (
DPoP-Nonceresponse header) with configurable TTL - JTI replay prevention with database-backed store + background purge
ath(access token hash) validation on resource requests- Backward compatible: no DPoP proof → standard Bearer token
- Introspection returns
cnf.jktfor DPoP-bound tokens - AS metadata advertises
dpop_signing_alg_values_supported
Configuration: dpop.enabled: true (disabled by default).
Token exchange
RFC 8693 — OAuth 2.0 Token Exchange
Full support for impersonation and delegation flows.
Coverage:
grant_type=urn:ietf:params:oauth:grant-type:token-exchange- Subject token validation: signature, issuer, expiry, revocation
- Subject token types:
access_token,jwtURNs - Impersonation: no actor token, no
actclaim,subpreserved - Delegation: actor token present, nested
actclaim per §4.1 - Multi-hop delegation: correct chain nesting
- Scope narrowing: requested scope must be subset of subject-token scope
- Configurable chain depth limit (1-10, default 5)
- Per-resource policy enforcement (
policy.exchange.allowed_client_ids) - Self-exchange guarded by
token_exchange.allow_self_exchange - DPoP binding propagation on exchanged tokens
- AS metadata:
grant_types_supportedincludes the URN
Configuration: token_exchange.enabled: true (disabled by default).
AuthPlane extensions
JWT Bearer + XAA (RFC 7523 + ID-JAG assertion profile)
Enterprise-Managed Authorization via JWT Bearer grant with the ID-JAG assertion format — an emerging IETF/OIDF draft referenced by the MCP Authorization spec (2025-11-25).
Coverage:
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer- ID-JAG assertion validation: signature, issuer, audience, expiry, type header (
oauth-id-jag+jwt) - Trusted IdP registry with JWKS discovery + caching (SSRF-protected)
- Policy engine: IdP + client_id + scope + resource constraint evaluation
- Subject mapping:
auto_map(federated subject) andstrict(explicit mapping required) modes - Replay prevention: assertion JTI single-use enforcement + auto-purge
- Scope intersection: policy scopes narrow the issued token’s scope
- Resource binding:
resourceparameter flows to tokenaudclaim - DPoP binding: XAA tokens support
cnf.jkt - Machine token storage for revocation/introspection
- AS metadata:
grant_types_supportedincludesjwt-bearerURN when enabled
Configuration: xaa.enabled: true (disabled by default). YAML-only at v0.1.x — no env-var overrides.
No deviations from RFC 7523 §2.1 (JWT assertion profile).
Agent identity claims
AuthPlane-specific JWT extensions:
agent_id— set toclient_idwhen issuing client hasis_agent=trueagent_chain— ordered list built from delegationactchain, capped at 8- Agent registration via DCR (
agent: true,agent_descriptionmax 255 chars) - Optional JWKS agent listing (
agents.enable_jwks_listing: true) - AS metadata advertises
authplane_agent_identity_supported: true
Not standardized. See Concepts: Agent identity.
MCP-specific
MCP Authorization Specification (2025-11-25)
Implemented: Full discovery flow (PRM → AS Metadata → DCR → Authorize → Token), CIMD support, resource indicators, DPoP-bound tokens.
Tested against: Claude Code, Claude Desktop, MCP Inspector. Cursor and VS Code interop is documented for guidance but not yet in the regression set — status Pending in the compatibility matrix.
OAuth 2.1 itself remains an active IETF draft (draft-ietf-oauth-v2-1) rather than a published RFC — AuthPlane tracks the latest revision.
Summary matrix
Related
- Reference: Configuration — every
*.enabledflag from the table above - Reference: Errors — RFC 9457 problem+json shape +
WWW-Authenticatecatalog - Reference: Public API — the endpoints each RFC lives on
- Concepts: Grants & flows — RFC-by-RFC mapping to actual flows
- Test matrix —
authserver/wiki/COMPLIANCE_TEST_MATRIX.md— one test row per RFC section - Design decisions —
authserver/wiki/DECISIONS.md— ADRs referenced above