Application Level Proof of Possession for Access Tokens

Sadil Chamishka
6 min readOct 10, 2022

The OAuth 2.0 framework introduced a mechanism to delegate resource access for a third party on behalf of the resource owner. This paradigm revolutionised the authorization flows in the software applications and yet it is the de facto standard for access delegation. The traditional approach of sharing resource owner’s credentials with the third parties involved major security threat and OAuth 2.0 framework addressed the problem by giving fine grained access for third party application, more specifically on resource owner’s consent. The OAuth 2.0 framework does not evaluate the possession of the token holder, hence the access token has to be keep confidential during its expiry time.

This leads to a security loophole for the attackers to hijack the access tokens specially from the public clients like browser based applications and pretend to be the token owner. In case of compromised tokens, normally the severity is lower compared to a user credential breach. But, there can be situations where the applications are protected by multi-factor authentication techniques and the compromised token would result in severe impact than a password breach. Therefore the applications which hold sensitive and financial data have to be protected with extensive care. The Proof of Possession techniques comes in handy to provide an extra layer of security for the access token. In this blog, I am going to explain the OAuth 2.0 Demonstration of Proof-of-Possession (DPoP) which is one of the widely used proof of possession technique.

OAuth 2.0 Demonstration of Proof-of-Possession (DPoP)

The usual bearer tokens which implies the bearer of the token can simply access the resources but no need any proof of possession. The DPoP works in application layer to prove the possession of a public/private key pair in order to constraint the authority to an access token issued by the authorization server to be used only for that particular sender who initiated the access token request. The key pair is generated by cryptographic techniques and send the public key along with the access token request and the authorization server will issue an access token binding the particular public key into that token. The preceding requests to access resources will be only allowed for the owner of the private key of the public key which is bounded to the access token.

Let’s walk through the DPoP token flow with more details and understand how to enable the WSO2 Identity server 6.0 to support DPoP. The WSO2 Identity Server 6.0 is an industry standard identity and access management solution which comes with lot of customizations including the support for the OAuth 2.0 DPoP standards.

First of all the client application has to generate a cryptographic key pair. The access token request is sent to the identity server along with a proof JWT as a HTTP header as shown in below figure. The DPoP proof JWT consists public key, payload and the signed payload by the private key.

Access token request flow.

The header part of the DPoP proof JWT is as follows.

{
"typ":"dpop+jwt",
"alg":"ES256",
"jwk": {
"kty":"EC",
"x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
"y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
"crv":"P-256"
}
}
  • typ — A fixed string, “dpop+jwt”.
  • alg — A signature algorithm.
  • jwk — A public key that the client chooses.

The payload part of DPoP proof JWT is as follows.

{
"jti":"-BwC3ESc6acc2lTc",
"htm":"POST",
"htu":"https://localhost:9443/token",
"iat":1562262616
}
  • jti — A unique identifier of the JWT.
  • htm — The HTTP method of the request.
  • htu — The URL of the request.
  • iat — The time at which the JWT is issued.

The identity server can extract the public key from the DPoP proof header and verify the signature (The signature verification happen by decrypting the signature by the public key and match with the payload). This step verifies that the private key is owned by the sender of the token request. Then identity server issues an access token and bind the public key to the corresponding token. The token binding is achieved by including the hash of the public key as an identity claim of the access token in the “jkt” claim under the “cnf” claim.

"cnf": {
"jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I"
}

The DPoP proof JWT consist of very short expiry time to increase the security. Hence, each time the client application access the resource server to access a resource, it is needed to send a DPoP proof along with the access token. The DPoP proof is generated as discussed above by signing the payload by the private key and sending the constructed JWT as and HTTP header called DPoP as shown in below figure.

OAuth 2.0 protected resource access with DPoP.

The normal OAuth 2.0 protected resources are accessed by “Authorization” HTTP header with Bearer prefix and the access token.

Authorization: Bearer <Access-Token>

The DPoP protected resources are accessed by the “Authorization” header with DPoP prefixed access token and the DPoP proof JWT which passed as additional HTTP header as proof of possession of the access token.

Authorization: DPoP <Access-Token>
DPoP: <Proof JWT>

When request to access a resource, the resource server extract the public key from the DPoP proof JWT and check the signature to verify the private key is hold by the request sender. Then the resource server introspects the retrieved token from the identity server and introspection response includes the public key of the token which is bound. The resource server allow access for the requested resource after comparing the public keys.

At the moment DPoP specification is in draft state and is currently available as an extension for the WSO2 Identity Server. Let’s see how to configure the WSO2 Identity Server 6.0 to support DPoP protected resource access.

  • Build the project in this GitHub repository.
  • Download the WSO2 IS 6.0 from here and extract into a folder (Configure directory path as IS_HOME).
  • Copy the build jar file into the “<IS_HOME>/repository/components/dropins” folder.
  • Add the following configurations into the deployment.toml file in “<IS_HOME>/repository/conf” directory.
[[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
properties.skip_dpop_validation_in_revoke = "true"

[[oauth.custom_token_validator]]
type = "dpop"
class="org.wso2.carbon.identity.dpop.validators.DPoPTokenValidator"
  • Start the server by running “<IS_HOME>/bin/wso2server.sh”.
  • Create a service provider app and navigate to inbound authentication configuration as shown below figure.
Create service provider
Navigate to inbound authentication configurations of the selected service provider application.
  • Select DPoP based Access Token Binding and enable validate token bindings option also as shown in below figure.

You can try out the OAuth 2.0 DPoP flow as discussed in this blog by generating a proof JWT (Try this sample code to generate proof JWT to try out this feature) and invoking “token” endpoint and the OAuth 2.0 protected REST APIs of the WSO2 identity server.

References

--

--