PE
Protocol Explorer
OAuth 2.0 DPoP

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.

RFC 9449
Client ApplicationAuthz ServerResource Server1POST /token2002POST /protected
POST https://auth.example.com/token200

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'.

1 / 2
speed

Step 1: POST /token

Request / response
POSThttps://auth.example.com/token
Content-Type?

application/x-www-form-urlencoded

DPoP

eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwieCI6Imw4QkZk…

Body
grant_type=authorization_code&code=SPLIT_123&client_id=my_client
Cryptographic Signature

Construction Steps

1. 1. Build JWT Header (includes Public Key)
{
  "typ": "dpop+jwt",
  "alg": "ES256",
  "jwk": {
    "kty": "EC",
    "x": "l8BFdamQrm6UmuEPY6r1qyJDlb3Ut3jXWiuKn4-GR3A",
    "y": "_eKPsI_use_2fkzDjhhqq8qVe_2oVvIo5jLQ3Mh41uM",
    "crv": "P-256"
  }
}
2. 2. Build JWT Payload
{
  "jti": "-BwC0eAMZea5GpZD",
  "htm": "POST",
  "htu": "https://auth.example.com/token",
  "iat": 1562262616
}
3. 3. Sign JWT
ES256(Base64Url(Header) + "." + Base64Url(Payload), PrivateKey) → Signature

Signature Base String

eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwieCI6Imw4QkZkYW1Rcm02VW11RVBZNnIxcXlKRGxiM1V0M2pYV2l1S240LUdSM0EiLCJ5IjoiX2VLUHNJX3VzZV8yZmt6akRqaHFxOHFWZV8yb1Z2SW81akxRM01oNDF1TSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDMGVBTVplYTVHcFpEIiwiaHRtIjoiUE9TVCIsImh0dSI6Imh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbS90b2tlbiIsImlhdCI6MTU2MjI2MjYxNn0

Signing Key

Client's ES256 Private Key

Signature Output

2-G04T...
DPoP Proofdpop+jwt
Header
{
"typ"?:"dpop+jwt",
"alg":"ES256",
"jwk"?:{
"kty":"EC",
"x":"l8BFdamQrm6UmuEPY6r1qyJDlb3Ut3jXWiuKn4-GR3A",
"y":"_eKPsI_use_2fkzDjhhqq8qVe_2oVvIo5jLQ3Mh41uM",
"crv":"P-256"
}
}
Payload
{
"jti"?:"-BwC0eAMZea5GpZD",
"htm":"POST",
"htu":"https://auth.example.com/token",
"iat"?:1562262616
}
sig: 2-G04T...
Access Tokenat+jwt
Header
{
"typ"?:"at+jwt",
"alg":"ES256"
}
Payload
{
"iss"?:"https://auth.example.com",
"sub"?:"user123",
"aud"?:"https://api.example.com",
"exp"?:1562266216,
"iat"?:1562262616,
"cnf"?:{
"jkt":"0Zhm7PMUXy83vmvouFfHFa2tYqMwYUh7iCpVXjRo6Sc"
}
}
sig: mock_sig