modelcontextprotocol / modelcontextprotocol/conformance
Server Auth: DPoP Proof Validation (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 access tokens. When a client
presents a DPoP-bound token, the MCP server (resource server) must verify a
DPoP proof on every request before granting access.
This issue covers MCP server conformance only. It validates that a server
acting as an OAuth 2.1 resource server correctly applies the RFC 9449 §4.3 proof
checking steps, enforces the ±5-minute iat acceptance window, returns correct
401 / WWW-Authenticate: DPoP challenges, and continues to enforce the baseline
token audience requirements.
Key properties of the server role:
- The framework drives the server as a DPoP client, presenting valid proofs
for positive checks and deliberately malformed proofs for negative checks. - The proposal adopts DPoP as defined in RFC 9449 — no MCP-specific extensions
to proof validation are expected. - A conformant stateless server provides replay protection via the
iatwindow
and standard claim validation;jtitracking and nonces are optional.
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.2 DPoP Proof JWT Syntax, §4.3 Checking DPoP Proofs (the core checklist)
- §6 Public Key Confirmation (
cnf/jkt), §7 DPoP-bound access tokens - §7.1 The DPoP Authentication Scheme and
WWW-Authenticatechallenge - §9 Resource Server-Provided Nonce, §11.1 DPoP Proof Replay
- Baseline MCP Authorization specification (resource-server token validation and
audience binding): https://modelcontextprotocol.io/specification/draft/basic/authorization
Scope
In scope — what the MCP/resource server does:
- Requiring the
DPoPAuthorizationscheme and aDPoPproof header on
protected requests. - Applying every RFC 9449 §4.3 proof-checking step.
- Enforcing the ±5-minute
iatacceptance window. - Confirming the access token is bound to the proof key (
cnf/jktagreement). - Returning correct
401responses with aWWW-Authenticate: DPoPchallenge
(including thealgsparameter and the appropriateerrorcode). - Optional server-provided nonce issuance and enforcement.
- Continuing to enforce baseline token audience validation when DPoP is used.
Not in scope (covered elsewhere or by another role):
- Client proof construction and nonce-retry behaviour — covered by the client
conformance issue. - Authorization-server token binding, metadata, and token-endpoint nonce —
covered by the authorization-server conformance issue. - Cryptographic algorithm policy beyond rejecting
none/symmetric algorithms.
Changes Required
Conformance harness (framework acting as a DPoP client)
- The framework, acting as a DPoP client, presents a DPoP-bound access
token (Authorization: DPoP <token>) plus aDPoPproof to the server under
test. - Fixture generation for: a valid key pair, a DPoP-bound access token whose
cnf.jktmatches the proof key and whose audience matches the server under
test, and a matched valid proof. - A library of crafted invalid proofs, one per §4.3 failure mode, each
designed to trigger a specific rejection so the server's response is
predetermined.
Test authorization server (createAuthServer)
- Mint DPoP-bound access tokens (correct audience,
cnf.jkt) for the server under
test to validate. Only needed to the extent the server requires a trusted,
audience-correct token to reach the proof-validation path.
Helpers (helpers/)
- DPoP proof builder with per-field overrides (so each negative fixture can
perturb exactly one claim/header: wronghtu, wronghtm, stale/futureiat,
missingjti,typ != dpop+jwt,alg=none/symmetric, private key injwk,
bad signature, wrong/absentath, duplicateDPoPheader, mismatched
cnf/jkt). - JWK SHA-256 thumbprint and
athhelpers.
Scenario (src/scenarios/server/)
- A single scenario file implementing all checks below, registered in the server
scenario list.
Acceptance test suite
- Helper unit tests (proof builder field overrides, thumbprint,
ath), and
scenario acceptance tests asserting each check passes for a conformant server
and fails for a deliberately non-conformant one.
Components that do not change
- The MCP protocol/JSON-RPC interaction is unchanged; only the
Authorization
scheme and the addedDPoPproof verification differ.
Checks to Cover
Positive (valid proof accepted)
- A request with a valid DPoP-bound token and matching proof is accepted and
the MCP operation succeeds. - Server accepts a proof whose
iatis within the ±5-minute window.
Negative (RFC 9449 §4.3 — each rejected with 401 + WWW-Authenticate: DPoP error="invalid_dpop_proof" unless noted)
- More than one
DPoPheader field present. -
DPoPheader is not a single, well-formed JWT. - A required claim is missing (
jti,htm,htu,iat). -
typJOSE header is notdpop+jwt. -
algisnoneor a symmetric algorithm (or otherwise unacceptable). - Signature does not verify against the embedded
jwk. -
jwkJOSE header contains a private key. -
htmdoes not match the request method. -
htudoes not match the request target URI (ignoring query/fragment). -
iatis outside the acceptable window (stale and far-future both rejected). -
athis missing or does not equal the hash of the presented access token. - The access token's bound key (
cnf.jkt) does not match the proof's public
key → rejected witherror="invalid_token". - A DPoP-bound token presented with the
Bearerscheme is rejected. - Baseline: a token whose audience is not this server is rejected (
401),
even with an otherwise valid proof.
Optional nonce behaviour (only if the server advertises/requires nonces)
- Server issues
401 ... error="use_dpop_nonce"with aDPoP-Nonceheader
when it requires a nonce and none is present. - Server accepts the subsequent request carrying the matching
nonceclaim. - Server rejects a proof whose
noncedoes not match a recently supplied
value.
Challenge format
-
401responses carryWWW-Authenticate: DPoPand SHOULD include thealgs
parameter listing acceptable JWS algorithms.
Acceptance Criteria
- A single scenario file in
src/scenarios/server/implements all checks
above (one scenario, many checks). - Each §4.3 check has both a passing case (valid proof accepted) and a
deliberate failing case (crafted invalid proof rejected with the correct
status and error code) proven by the automated acceptance test suite. - Helper unit tests cover the proof builder's per-field overrides and the
thumbprint/athhelpers. - 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 SDK server implementation before the PR
is submitted; SDK baseline YAMLs updated where existing SDKs do not yet
support DPoP.
Out of Scope
- Required
jtistate-tracking / global replay store — optional per RFC 9449
§11.1. A stateless server relying on theiatwindow and claim validation is
conformant;jti-tracking is tested only as optional behaviour if advertised. - Server-side nonce cryptographic construction (e.g. AEAD-encrypted
timestamps) — an implementation choice; only the observable nonce challenge/
acceptance protocol is tested. - Client proof construction and authorization-server behaviour — covered by the
separate client and authorization-server conformance issues.
Notes
Prepared with the aid 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 with the existing scenario registration under src/scenarios/server/, the helpers/ area, and createAuthServer; read RFC 9449 §4.3 and run npm test to understand the conformance harness. Add one registered server scenario, proof and token fixtures, and helper unit tests covering the listed positive and negative checks. Done means the standard CLI runner and npm test pass, with the required status, challenge, and error assertions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, authentication, security, testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100