Skip to main content

Module dpop

Module dpop 

Source
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:

  • htu is 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 jwk is 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 Bearer and a DPoP challenge in ONE header, so reading the first error= 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 None if this is not a nonce challenge.
proof
Build a DPoP proof for one request.