Using DPoP

Preface


This article describes how to support "RFC 9449: OAuth 2.0 Demonstrating Proof-of-Possession (DPoP)" with Authlete APIs.





Instructions


Authorization servers and resource servers support DPoP by following these steps.

  1. Receiving a request that includes a "DPoP Proof JWT"
    • A endpoint (EP) of an authorization server (e.g., Token EP, PAR EP, UserInfo EP) or a resource server receives a request, with "DPoP Proof JWT" as one of HTTP headers, from a client. 
  2. Extracting DPoP-related information
    • The server extracts DPoP-related information (DPoP Proof JWT, HTTP method and HTTP target URI) from the request.
  3. Making a request to Authlete's APIs
    • The server make a request, that includes the content of the client's request and the above DPoP-related information as request parameters,  to Authlete APIs (/auth/token, /auth/introspection, etc.)

Example


The following is an example of how to support DPoP in an authorization server's token EP.

DPoP support on token EP


1. Receiving a request that includes a "DPoP Proof JWT"


Let us assume that the authorization server's token EP receives the following HTTP request. (wrapped for readability)

POST /token HTTP/1.1
Host: as.example.com
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7Imt0eSI6IlJTQSIs
      ImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoib3A4cTNIaUNPVHQtejBmUE1kanZs
      V21WN2QwS2FxVG9xcDNlZF9wdHA1QSIsImFsZyI6IlJTMjU2IiwibiI6ImdadHZ5VmRC
      b1ZEVTZHVTFLOGE2eHphb2EwR0F6dE9wcG1zRVZFN1NDZFpjT29WanpURlNRSnBXa0RQ
      QmktNzBmeHdtc041c016Q3RPeXZ1Sk5XcFk5RHFUb0lWYXBXM2VJOFRIU3dNNnZ0bXpN
      SWt5WDY0RXdZb2VuN2twbkhtZ3VDWUZ6dWxLM2FKZzJKWFpOWXl1YTFuTTRmSGs3TnA0
      UlhTYmFBb2p5THR0SVFCSXZpOFVPcVI1dEYwaXZCQzRKSGxnUDVZTjNjTjIxOEFqeTVm
      cHFJdi1naE0zcmhtZjJuZFNpWnU2R3JPNmdPOXFyaE05NXJRcEprSDlMcmdQaEE2ZkhQ
      WVB3WnR5dEpBVGNVd1FWTThKTmwybTFWRzlXS1o0SjdTTGJxdVNNNUZ4b29Oekc2dmZB
      WlhWLTBVTVBqSU5TZ3dJMDdBYi1OcnZBUHNKUSJ9fQ.eyJqdGkiOiItQndDM0VTYzZhY
      2MybFRjIiwiaHRtIjoiUE9TVCIsImh0dSI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20vd
      G9rZW4iLCJpYXQiOjE2NzkzMDg3NDN9.VOoyMJVR5RwyOWDGF42Oc_AElsGf6x2ZLW-X
      Y8g8xXbH7WMdGKeSY0Mm8YIXblviyBCgD0y6oQH07Ds5uEtH0GSO15z5brawJmivrUyi
      IiaH6UK2GKE42HNHrQ29Ln66cEqbDYxizN4hfu9yqoQgGEw6oRhiQaOLDLyzGEQQRMkB
      PEz2LwhfsUhSzWPjtyhj2WBobH5WaNCybo6SBI2eGj1Pj97PdREK0luR7rn3AU_N-PtI
      DFNeXbtYjRcE6NNrfSCWcrkLcuOHuKgPv61-OuqQ0jRbLpkyhTWjxtmjzOuzWspfvg8l
      n8bOaw_y4VOspvUL5FBGI6P-RXBlBUrKow
...

grant_type=authorization_code&scope=read&
 redirect_uri={redirect_uri}&code={code}&client_id={client_id}


2. Extracting DPoP-related information


The authorization server detects a DPoP header in the request, and extracts HTTP method, HTTP target URI and DPoP Proof JWT. These values are then included in a request to Authlete's /auth/token API, as htm, htu and dpop respectively.

The following table shows the values in this example.
Item
Value
Method (htm)
POST
Target URI (htu)
https://as.example.com/token
DPoP Proof JWT (dpop)
eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7Imt0eSI6IlJTQSIs
ImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoib3A4cTNIaUNPVHQtejBmUE1kanZs
V21WN2QwS2FxVG9xcDNlZF9wdHA1QSIsImFsZyI6IlJTMjU2IiwibiI6ImdadHZ5VmRC
b1ZEVTZHVTFLOGE2eHphb2EwR0F6dE9wcG1zRVZFN1NDZFpjT29WanpURlNRSnBXa0RQ
QmktNzBmeHdtc041c016Q3RPeXZ1Sk5XcFk5RHFUb0lWYXBXM2VJOFRIU3dNNnZ0bXpN
SWt5WDY0RXdZb2VuN2twbkhtZ3VDWUZ6dWxLM2FKZzJKWFpOWXl1YTFuTTRmSGs3TnA0
UlhTYmFBb2p5THR0SVFCSXZpOFVPcVI1dEYwaXZCQzRKSGxnUDVZTjNjTjIxOEFqeTVm
cHFJdi1naE0zcmhtZjJuZFNpWnU2R3JPNmdPOXFyaE05NXJRcEprSDlMcmdQaEE2ZkhQ
WVB3WnR5dEpBVGNVd1FWTThKTmwybTFWRzlXS1o0SjdTTGJxdVNNNUZ4b29Oekc2dmZB
WlhWLTBVTVBqSU5TZ3dJMDdBYi1OcnZBUHNKUSJ9fQ.eyJqdGkiOiItQndDM0VTYzZhY
2MybFRjIiwiaHRtIjoiUE9TVCIsImh0dSI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20vd
G9rZW4iLCJpYXQiOjE2NzkzMDg3NDN9.VOoyMJVR5RwyOWDGF42Oc_AElsGf6x2ZLW-X
Y8g8xXbH7WMdGKeSY0Mm8YIXblviyBCgD0y6oQH07Ds5uEtH0GSO15z5brawJmivrUyi
IiaH6UK2GKE42HNHrQ29Ln66cEqbDYxizN4hfu9yqoQgGEw6oRhiQaOLDLyzGEQQRMkB
PEz2LwhfsUhSzWPjtyhj2WBobH5WaNCybo6SBI2eGj1Pj97PdREK0luR7rn3AU_N-PtI
DFNeXbtYjRcE6NNrfSCWcrkLcuOHuKgPv61-OuqQ0jRbLpkyhTWjxtmjzOuzWspfvg8l
n8bOaw_y4VOspvUL5FBGI6P-RXBlBUrKow



3. Making a request to Authlete's APIs


The following is a request body from the authorization server to the /auth/token API.

{
  "parameters": "grant_type=authorization_code&scope=read&
                 redirect_uri={redirect_uri}&code={code}&client_id={client_id}",
  "htm":"POST", 
  "htu":"https://as.example.com/token",
  "dpop":"eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7Imt0eSI6IlJTQSIs
          ImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoib3A4cTNIaUNPVHQtejBmUE1kanZs
          V21WN2QwS2FxVG9xcDNlZF9wdHA1QSIsImFsZyI6IlJTMjU2IiwibiI6ImdadHZ5VmRC
          b1ZEVTZHVTFLOGE2eHphb2EwR0F6dE9wcG1zRVZFN1NDZFpjT29WanpURlNRSnBXa0RQ
          QmktNzBmeHdtc041c016Q3RPeXZ1Sk5XcFk5RHFUb0lWYXBXM2VJOFRIU3dNNnZ0bXpN
          SWt5WDY0RXdZb2VuN2twbkhtZ3VDWUZ6dWxLM2FKZzJKWFpOWXl1YTFuTTRmSGs3TnA0
          UlhTYmFBb2p5THR0SVFCSXZpOFVPcVI1dEYwaXZCQzRKSGxnUDVZTjNjTjIxOEFqeTVm
          cHFJdi1naE0zcmhtZjJuZFNpWnU2R3JPNmdPOXFyaE05NXJRcEprSDlMcmdQaEE2ZkhQ
          WVB3WnR5dEpBVGNVd1FWTThKTmwybTFWRzlXS1o0SjdTTGJxdVNNNUZ4b29Oekc2dmZB
          WlhWLTBVTVBqSU5TZ3dJMDdBYi1OcnZBUHNKUSJ9fQ.eyJqdGkiOiItQndDM0VTYzZhY
          2MybFRjIiwiaHRtIjoiUE9TVCIsImh0dSI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20vd
          G9rZW4iLCJpYXQiOjE2NzkzMDg3NDN9.VOoyMJVR5RwyOWDGF42Oc_AElsGf6x2ZLW-X
          Y8g8xXbH7WMdGKeSY0Mm8YIXblviyBCgD0y6oQH07Ds5uEtH0GSO15z5brawJmivrUyi
          IiaH6UK2GKE42HNHrQ29Ln66cEqbDYxizN4hfu9yqoQgGEw6oRhiQaOLDLyzGEQQRMkB
          PEz2LwhfsUhSzWPjtyhj2WBobH5WaNCybo6SBI2eGj1Pj97PdREK0luR7rn3AU_N-PtI
          DFNeXbtYjRcE6NNrfSCWcrkLcuOHuKgPv61-OuqQ0jRbLpkyhTWjxtmjzOuzWspfvg8l
          n8bOaw_y4VOspvUL5FBGI6P-RXBlBUrKow"
}

Authlete returns the following response if the above request is successful.

{
  "type": "tokenResponse",
  "resultCode": "A050001",
  "resultMessage": "[A050001] The token request (grant_type=authorization_code)
                    was processed successfully.",
  "accessToken": "{access_token}",
  "action": "OK",
  "responseContent": 
    "{\"access_token\":\"{access_token}\",
      \"scope\":\"read\",\"token_type\":\"DPoP\",\"expires_in\":60}",
...
}

The authorization server will then return a token response to the client with responseContent as its body.
How did we do with this article?