OAuth 2.0 DPoP — Full Flow
Demonstrating Proof-of-Possession (DPoP) at the application layer. The client generates a DPoP proof to bind the access token to a private key, preventing token replay.
The client requests an access token and includes a DPoP header. The DPoP header is a signed JWT containing the client's public key (in the jwk header) and the HTTP request details (htm, htu in payload).
• The Authorization Server validates the DPoP proof's signature.
• It then binds the issued access token to the public key by embedding its JWK Thumbprint (RFC 7638) in the 'cnf' claim of the token.
• The token_type in the response is 'DPoP' rather than 'Bearer'.
Step 1: POST /token
application/x-www-form-urlencoded
eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwieCI6Imw4QkZk…
grant_type=authorization_code&code=SPLIT_123&client_id=my_client
Construction Steps
{
"typ": "dpop+jwt",
"alg": "ES256",
"jwk": {
"kty": "EC",
"x": "l8BFdamQrm6UmuEPY6r1qyJDlb3Ut3jXWiuKn4-GR3A",
"y": "_eKPsI_use_2fkzDjhhqq8qVe_2oVvIo5jLQ3Mh41uM",
"crv": "P-256"
}
}{
"jti": "-BwC0eAMZea5GpZD",
"htm": "POST",
"htu": "https://auth.example.com/token",
"iat": 1562262616
}ES256(Base64Url(Header) + "." + Base64Url(Payload), PrivateKey) → Signature
Signature Base String
eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwieCI6Imw4QkZkYW1Rcm02VW11RVBZNnIxcXlKRGxiM1V0M2pYV2l1S240LUdSM0EiLCJ5IjoiX2VLUHNJX3VzZV8yZmt6akRqaHFxOHFWZV8yb1Z2SW81akxRM01oNDF1TSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDMGVBTVplYTVHcFpEIiwiaHRtIjoiUE9TVCIsImh0dSI6Imh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbS90b2tlbiIsImlhdCI6MTU2MjI2MjYxNn0
Signing Key
Client's ES256 Private KeySignature Output
2-G04T...{"typ"?:"dpop+jwt","alg":"ES256","jwk"?:{"kty":"EC","x":"l8BFdamQrm6UmuEPY6r1qyJDlb3Ut3jXWiuKn4-GR3A","y":"_eKPsI_use_2fkzDjhhqq8qVe_2oVvIo5jLQ3Mh41uM","crv":"P-256"}}{"jti"?:"-BwC0eAMZea5GpZD","htm":"POST","htu":"https://auth.example.com/token","iat"?:1562262616}{"typ"?:"at+jwt","alg":"ES256"}{"iss"?:"https://auth.example.com","sub"?:"user123","aud"?:"https://api.example.com","exp"?:1562266216,"iat"?:1562262616,"cnf"?:{"jkt":"0Zhm7PMUXy83vmvouFfHFa2tYqMwYUh7iCpVXjRo6Sc"}}