modelcontextprotocol / modelcontextprotocol/conformance
Authorization Server Auth: DPoP Token Binding (SEP-1932)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 127
- Forks
- 101
- Avg merge
- 6d 1h
- Merged PRs (30d)
- 7
Description
Overview
SEP-1932
adopts OAuth 2.0 Demonstrating Proof of Possession
(RFC 9449) as an optional MCP
authorization extension. For sender-constrained tokens to work, the OAuth
authorization server must accept a DPoP proof at the token endpoint, bind the
issued access token to the client's public key, and advertise its DPoP support.
This issue covers authorization server conformance only. It validates that an
authorization server advertises dpop_signing_alg_values_supported, validates the
token-endpoint DPoP proof, issues a DPoP-bound token (token_type=DPoP with a
cnf.jkt confirmation), honours the optional nonce mechanism, and enforces
dpop_bound_access_tokens client registration.
Key properties of the authorization-server role:
- The framework drives the authorization server as a DPoP client at the token
endpoint, presenting valid and invalid proofs. - DPoP is adopted as defined in RFC 9449 — no MCP-specific extensions to the
token-endpoint exchange. - This is distinct from client and resource-server conformance even though all
three involve OAuth; the authorization server is tested in isolation.
Specification References
- SEP-1932 PR: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1932
- Detailed proposal: https://github.com/modelcontextprotocol/ext-auth/blob/pieterkas-dpop-extension/specification/draft/dpop-extension.mdx
- RFC 9449 — OAuth 2.0 Demonstrating Proof of Possession (DPoP): https://www.rfc-editor.org/rfc/rfc9449.html
- §4.3 Checking DPoP Proofs (token-endpoint validation), §5 DPoP Access Token Request
- §6 Public Key Confirmation (
cnf/jkt) - §5.1
dpop_signing_alg_values_supported, §5.2dpop_bound_access_tokens - §8 Authorization Server-Provided Nonce
- RFC 8414 — OAuth 2.0 Authorization Server Metadata: https://datatracker.ietf.org/doc/html/rfc8414
- Baseline MCP Authorization specification: https://modelcontextprotocol.io/specification/draft/basic/authorization
Scope
In scope — what the authorization server does:
- Advertising
dpop_signing_alg_values_supported(asymmetric algorithms only; no
none) in its authorization server metadata. - Validating the DPoP proof presented on the token request (§4.3 as applicable to
the token endpoint:typ,alg, signature,jwkwithout private key,
htm=POST,htu=token endpoint,jti,iatwindow,noncewhen required). - Issuing a DPoP-bound access token:
token_typeofDPoPand acnf.jkt
confirmation equal to the base64url JWK SHA-256 thumbprint of the proof key. - Token-endpoint nonce mechanism:
400 use_dpop_nonce+DPoP-Nonce, then
accepting the retried request. - Honouring
dpop_bound_access_tokens=trueclient registration by rejecting token
requests that lack a DPoP proof. (Excluded — requires dynamic client registration, out of scope for these DPoP scenarios; see #396.) - Binding refresh tokens to the same key for public clients. (Deferred — not testable until the shared conformance test AS supports refresh tokens; tracked as a follow-up. See #396.)
Not in scope (covered elsewhere or by another role):
- Resource-server proof validation and
ath/cnfagreement at resource access —
covered by the server conformance issue. - Client proof construction and nonce-retry behaviour — covered by the client
conformance issue.
Changes Required
Conformance harness (framework acting as a DPoP client at the token endpoint)
- The framework, acting as a DPoP client, performs a token request with a
DPoP proof against the authorization server under test, then inspects the
metadata, the token response (token_type), and the issued token'scnf.jkt. - Fixture generation for a valid proof keyed to a generated key pair, plus crafted
invalid proofs (one per token-endpoint failure mode).
Helpers (helpers/)
- DPoP proof builder with per-field overrides (reused from / shared with the
server scenario helpers where practical). - JWK SHA-256 thumbprint helper to assert
cnf.jktequals the proof key
thumbprint. - Metadata fetch/parse helper for
dpop_signing_alg_values_supported.
Scenario (src/scenarios/authorization-server/)
- A single scenario file implementing all checks below, registered in the
authorization-server scenario list.
Acceptance test suite
- Helper unit tests and scenario acceptance tests asserting each check passes for
a conformant authorization server and fails for a deliberately non-conformant
one.
Components that do not change
- The resource-server (MCP server) path — the grant/token type does not change how
a resource server validates an access token's audience. - OIDC discovery infrastructure beyond surfacing the new metadata field.
Checks to Cover
Positive
- Metadata advertises
dpop_signing_alg_values_supportedas a JSON array of
asymmetric JWSalgvalues;noneis not present. - Token endpoint accepts a valid DPoP proof (
typ=dpop+jwt, asymmetricalg,
embedded publicjwk,htm=POST,htu=token endpoint,jti,iatin
window) and issues a token. - Issued token response sets
token_typetoDPoP. - Issued token carries a
cnf.jktequal to the base64url JWK SHA-256
thumbprint of the proof's public key. (Verified for JWT access tokens; opaque/reference tokens are out of scope —cnf.jktisn't observable without introspection; see #396.) - For a public client, an issued refresh token is bound to the same key. (Deferred to a follow-up. The shared test AS does not yet support refresh tokens; see #396.)
Negative (token-endpoint proof failures → 400 invalid_dpop_proof unless noted)
- Proof signature does not verify against the embedded
jwk. -
typis notdpop+jwt. -
algisnoneor a symmetric algorithm. -
jwkcontains a private key. -
htm/htudo not match the token endpoint request. -
iatis outside the acceptable window. - A required claim is missing (
jti,htm,htu,iat).
Nonce behaviour (if the authorization server requires nonces)
- Returns
400 use_dpop_nonce+DPoP-Noncewhen a nonce is required and
absent. - Accepts the retried token request carrying the matching
nonceclaim. - Rejects a proof whose
noncedoes not match a recently supplied value.
Client registration enforcement
- With
dpop_bound_access_tokens=true, the authorization server rejects a
token request that does not include a DPoP proof. (Excluded — depends on dynamic client registration; see #396.)
Acceptance Criteria
- A single scenario file in
src/scenarios/authorization-server/implements
all checks above (one scenario, many checks). - Each check has both a passing case (conformant authorization server) and a
deliberate failing case (crafted invalid proof / missing field) proven by the
automated acceptance test suite — no check is vacuously passing. - Helper unit tests cover the proof builder, thumbprint, and metadata helpers.
- The acceptance test suite runs as part of
npm test. - Scenario runs through the standard CLI runner; no parallel entry point is
introduced. - Validated against at least one real authorization server implementation
before the PR is submitted; SDK/AS baseline YAMLs updated where existing
implementations do not yet support DPoP.
Out of Scope
- Nonce cryptographic construction (e.g. AEAD-encrypted timestamps) — an
implementation choice; only the observableuse_dpop_nonceprotocol is tested. - Full OAuth 2.1 / token-endpoint conformance unrelated to DPoP (PKCE, resource
indicators, etc.) — covered by existing baseline authorization conformance. - Resource-server and client behaviour — covered by the separate server and
client conformance issues.
Notes
Prepared with the help of Claude (Opus 4.8)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the existing helpers/ and the authorization-server scenarios under src/scenarios/authorization-server/, then inspect how scenarios are registered and run through the standard CLI. Implement the DPoP helper, thumbprint and metadata checks, proof failure cases, nonce behavior, and acceptance tests described here. Done means npm test covers passing and deliberately failing cases, with the scenario registered and documented implementations validated.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, authentication, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100