Generate an asymmetric key pair (ES256 or RS256) in the client at startup or per session; this key is the DPoP key — never reuse it across users
For each request to the authorization server's token endpoint, create a DPoP proof JWT: header {typ: 'dpop+jwt', alg, jwk (public key)}, payload {jti (unique per proof), htm (HTTP method), htu (URL without query), iat, nonce if required}
Send the proof as a DPoP header in the token request; the AS validates the proof and issues a token with a cnf.jkt claim containing the SHA-256 thumbprint of the DPoP public key
For API requests, include both the Bearer/DPoP access token (Authorization: DPoP <token>) and a new DPoP proof JWT with ath (hash of the access token) in the payload
Handle the DPoP nonce challenge: if the AS returns a use_dpop_nonce error with a DPoP-Nonce header, retry the request including the nonce in the proof JWT payload
At the resource server, verify the DPoP proof signature, check that htm/htu match the current request, validate iat recency (max ~60 seconds), confirm the access token's cnf.jkt matches the JWK thumbprint in the proof
Known gotchas
The jti claim in the DPoP proof must be unique per request and checked for replay by the server within the iat validity window; a missing jti replay check makes DPoP ineffective
The htu value must match exactly the endpoint URL without query string or fragment; use the token endpoint URL for token requests and the API URL for resource requests
DPoP proofs are bound to a single request; do not cache and reuse a proof across requests — each call requires a freshly generated proof JWT
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp