Why this workflow has no DPoP switch
DPoP (RFC 9449) sender-constrains an OAuth access token. OpenID4VP does not mention DPoP at all, and the reason is structural rather than an omission: in its own words, “the result of an OpenID4VP interaction is one or more Verifiable Presentations and/or Presentations in the same or different Credential formats … instead of an Access Token”. There is no token in this exchange to bind.
What plays the same role here is the Key Binding JWT (RFC 9901 section 4.3), and the parallel is close enough to be worth seeing side by side. Both are short-lived JWTs of their own media type, signed by a key the holder possesses, that commit to the specific request they accompany:
| | DPoP proof | Key Binding JWT |
| typ | dpop+jwt | kb+jwt |
| proves possession of | the key in the token's cnf.jkt | the key in the credential's cnf.jwk |
| freshness from | iat, jti, and a server nonce | the verifier's nonce and iat |
| bound to the recipient by | htu (the endpoint URI) | aud (the Client Identifier) |
| commits to the payload by | ath, the hash of the access token | sd_hash, the hash of the exact bytes sent |
So the wallet's proof of possession in a presentation is the KB-JWT, and the thing DPoP would have protected — a bearer token that anyone holding the bytes could spend — does not exist here. DPoP does apply to the issuance side, where there is an access token, and it is switched on there.