What D’Hack Is DPoP? – DZone Security

OAuth2.0/OpenID connect is considered the fastest-growing protocol used by many application developers for access delegation and single-sign-on. This is due to its flexibility and high security compared to other protocols in the market. In contrast, the world is full of hackers who are desperately looking for flaws that you make when developing an application. Single page applications or public clients which do not use MTLS secure transport layers are considered to be the most vulnerable source of an attack.

Standard Token Flow

Despite the application type, the standard OAuth2.0/OpenID connect flow is similar to the below diagram (Figure 2). There are three actors involved: Client, Resource Server, and Authorization Server. The client will initiate the authorization request. Upon user authentication, the authorization server will issue an access token and refresh token for the user with an expiry time. Then, the client can use these tokens to access the protected resource from the resource server.

Refreshing an Expired Access Token

At any point of this request flow, there is no way of validating the owner of the tokens and the user who requests resources. Considering all these concerns, the IETF has introduced DPoP as a demonstration of proof-of-possession, which is another mechanism that can be used when MTLS is not possible to use. DPoP is with used to detect replay attacks access and refresh tokens. This new specification is still in the internet-draft stage(5th version).

DPoP Flow

Basic DPop Flow

There is not much difference to the standard OAuth2.0 flow when you use DPoP. A DPoP which is a JWT proof will be sent as the header in the token request flow and the authorization server will issue an access token of token_type=DPoP that is bound to the public key thumbprint of the DPoP proof. Similarly, another DPoP will be generated with the same keys and used when calling the API with an access token to access the protected resource.

End to End DPoP Flow

End to End DPoP flow

  • The public client (mobile app or SP) has to first generate a public and private key pair (1).
  • Next, generate the DPoP proof JWT by embedding the public key in the header part. You can refer to the Java client as a sample to generate the DPoP (4).
  • Use this DPoP as the header in the token request call and call the authorization server (5).
  • The authorization server will first extract the DPoP header and validate the first DPoP (6).
  • Use the public key in the header part of the JWT and validate the signature of DPoP proof (7).
  • Next, validate the expiry time of DPoP proof and the endpoint information (htm and htu values).
  • If and only if all the DPoP validations pass, the access token is generated for the user (8).
  • Before issuing the access token, this access token will be bound to the public key thumbprint of the DPoP proof. This will tell that this access token and refresh token are issued for this public-private key pair or the client (9).
  • Once the access token and refresh token are received by the client, the client can use them to access a protected resource (10).
  • When calling an API, the client has to again generate a DPoP using the same private and public key pair that was used to get the access token (13).
  • Use this new DPoP proof as the DPoP header when calling the API to access the resource in the Resource Server (14).
  • The Resource Server next extracts the DPoP and does the DPoP proof validation (15).
  • Next, validate the signature of DPoP, expiry time, and endpoint information (16).
  • If and only if DPoP is validated, validate the access token.
    • If it is an opaque access token: Do the introspect and make sure the public key thumbprint that is bound to access token is the same as the thumbprint of the public key that is used to generate DPoP jtk value.
      { 
      	"nbf": 1615273872,
          "scope": "123 internal_user_mgt_list openid",
          "active": true,
          "cnf": 
          	{ "jtk": "Darzfuh83X001Ng4lVss0CJqgFuFqJU2dNR9-cRuR5Y" },
          "token_type": "DPoP",
          "exp": 1615277472,
          "iat": 1615273872,
          "client_id": "pgwSndy9TooIzz5tZeZzPTp3Gt0a", 
          "username": "admin@carbon.super" 
       }

    • If it is a JWT access token: Do the signature validation and public key thumbprint validation of the DPoP. Use the jtk value as shown below in the payload of the JWT access token.
"cnf": {

    "jtk": "uWkS3p9TSEL_bZks_1Xxh0mxSPeGCr4OtHO0mALRplM"

  }

  • Finally, the Resource Server will issue the protected resource for the access token.

Anatomy of DPoP

DPoP is a JWT that sends as a header in the Request. This JWT is of the type dpop + jwt which tells that this is a DPoP proof with a limited expiration time.

Header: Algorithm and Token Type

The header part of the JWT contains the JWT type and the algorithm (alg), which is used to encrypt or sign the JWT. This SHOULD NOT be NONE or Symmetric algorithm and the public key of the public-private key pair generated for the client.

The payload part of the DPoP contains the claims that need to be validated after the signature validation of the JWT.

  • jti is a unique identifier that helps to check for replay attacks.
  • iat is the DPoP validation period. This time should be really short: less than 90 seconds is recommended.
  • htm is the type of endpoint called, either a POST or GET or PATCH or PUT or DELETE
  • htu is the API request or the endpoint called

htm and htu values ​​of the DPoP should be validated to make sure the DPoP proof is not stolen or that it is not a replay attack.

You also can add many more claims to the payload if needed.

Requests and Response Formats With DPoP

Token Request

Token Request

The typical token request will contain a DPoP header with the DPoP proof.

Token Response

Token ResponseAn API Call With DPoP and Access Token

An API Call With DPoP and Access Token

The API call will have an additional DPoP header with the DPoP proof, and will be in the authorization header before the access token DPoP name should be mentioned as shown above.

How Does DPoP Work With the WSO2 Identity Server?

This exciting DPoP feature is now available with the WSO2 Identity Server from 5.10 onwards. If you are subscribed customer of WSO2 Identity Server you can get this with 5.10 and 5.11 via U2 WSO2 Updates. If you are a community user, then you can get this DPoP feature in our next WSO2 Identity Server 5.12.0 release.

To configure DPoP in WSO2 Identity Server:

[[event_listener]]
id = "dpop_listener"
type = "org.wso2.carbon.identity.core.handler.AbstractIdentityHandler"
name="org.wso2.carbon.identity.dpop.listener.OauthDPoPInterceptorHandlerProxy"
order = 13
enable = true
properties.header_validity_period = 90 #Validity of DPoP proof in seconds

[[oauth.custom_token_validator]]
type = "dpop"
class = "org.wso2.carbon.identity.dpop.validators.DPoPTokenValidator"

[oauth.grant_type.uma_ticket]
retrieve_uma_permission_info_through_introspection = true

  • Once you complete all the above steps, you can start the server or restart it.

Once the server has started, you can go to your OAuth2.0/OpenID Connect service provider that configured and enabled DPoP to your application.

OAuth/OpenID Connect Configuration

Next, select DPoP based token binding and tick on the validate token binding as shown below. This will enable DPoP for this OAuth client app.

DPoP based token binding

Now you can try out the token request flows with DPoP. This ReadMe will give you more information on the configurations of the DPoP extension.

Hope you enjoyed the WSO2 Identity Server’s new feature, DPoP, which is designed as a security mechanism for public clients who are unable to use MTLS!

Thank you for reading!

.

Leave a Comment