You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The AS acceptance suite never exercises authorization code binding. dpop_jkt does not appear anywhere in src/scenarios/authorization-server/ on main, so an AS that silently ignores the parameter — issuing a token for a jkt-bound code exchanged with a wrong-key proof — passes the suite today.
The attack this binding exists to stop: an attacker who steals an authorization code (referrer leak, log, open redirect) exchanges it with a DPoP proof from their own key. A conformant AS compares the proof key's thumbprint to the dpop_jkt from the authorization request and rejects; an AS that ignores the parameter issues the attacker a token bound to the attacker's key.
#523 adds the client side of this (does the client senddpop_jkt), and its test AS enforces the binding — but nothing tests a real AS under test for the enforcement itself. The counterpart SEP text (client SHOULD) is in modelcontextprotocol/ext-auth#35.
Spec text
RFC 9449 §10:
When a token request is received, the authorization server computes the JWK Thumbprint of the proof-of-possession public key in the DPoP proof and verifies that it matches the dpop_jkt parameter value in the authorization request. If they do not match, it MUST reject the request.
Add two probes to the authorization-server DPoP scenario (builds on the surface #525 touches). Both run the full flow with dpop_jkt = thumbprint of key A on the authorization request, then vary the token exchange:
Check
Token exchange
SUCCESS
WARNING
FAILURE
sep-1932-as-dpop-jkt-accepted
valid proof from key A
token issued
—
request rejected (RFC 6749 §3.1: unrecognized request parameters MUST be ignored, so rejecting the matching flow breaks every client that sends the parameter)
sep-1932-as-dpop-jkt-mismatch-rejected
valid proof from key B
request rejected
token issued — binding not enforced
—
Grading rationale for the WARNING: authorization code binding is a SHOULD in the MCP profile (modelcontextprotocol/ext-auth#35) and the dpop_jkt parameter is OPTIONAL in RFC 9449 §10, so an AS that issues a token on the mismatch has either not implemented an optional mechanism or implemented it without enforcement — indistinguishable from outside, and both correctly graded WARNING. This mirrors the client side in #523, where omitting dpop_jkt is likewise a SHOULD miss graded WARNING. An AS that rejects the mismatched exchange is enforcing RFC 9449 §10's MUST and passes.
@nbarbettini, flagging this issue as a natural follow-up to #523 / #525 once both land as the dpop_jkt tests don't cover AS scenarios at present.
Activity