Expand description
DPoP (RFC 9449) — proof-of-possession for the per-session key.
Every OAuth request carries a fresh DPoP proof: a short-lived JWS, signed
by the session’s own key, binding the request to that key. The access token
is issued bound to the key’s RFC 7638 thumbprint (jkt), so a stolen bearer
token is useless without the private half.
Three details are easy to get wrong and are pinned by tests here:
htuis the request URI with userinfo, query and fragment removed (RFC 9449 §4.2). Leaving any of them on means the proof does not match what the server canonicalizes, and every request is rejected — and userinfo would additionally sign a password into a claim sent in the clear.- the embedded
jwkis the PUBLIC key only. It is transmitted in the clear in the JWS header; a private member here would publish the session’s signing key to the PDS and to anything on the path. - a challenge belongs to its own scheme. RFC 9449 §7.2 has a resource
server returning a
Bearerand aDPoPchallenge in ONE header, so reading the firsterror=found attributes one scheme’s error to the other.
The server may demand a nonce at any time. That is normal operation, not an error: the caller retries ONCE with the supplied nonce.
It is signalled two different ways depending on which endpoint answered —
the authorization server uses a 400 and a JSON body, the resource server a
401 and a WWW-Authenticate header. Handling only the header misses every
challenge from PAR, token and refresh, which is everything this client talks
to first. See nonce_challenge.
Enums§
- Endpoint
- Which kind of endpoint produced a response.
Functions§
- nonce_
challenge - The nonce to retry the request with, or
Noneif this is not a nonce challenge. - proof
- Build a DPoP proof for one request.