OAuth 2.0 is now widely adopted, but some security concerns remain. Recently, two new specifications were released to improve OAuth 2.0 security and address some of these concerns: Demonstrating Proof of Possession (DPoP) and Step-Up Authentication Challenge Protocol. Let’s take a high-level look at them to understand how they work.
Demonstrating Proof of Possession (DPoP)
The most popular artifact associated with OAuth 2.0 is the access token. This token, as well as the refresh token, is a bearer token, and there is a specification on how to use it. As mentioned in that specification, a fundamental feature of a bearer token is "that any party in possession of the token (a "bearer") can use the token in any way that any other party in possession of it can."
While this feature simplifies the token management, it raises some security concerns. In fact, if a bad actor manages to steal an access token, they can use it without any problem. Therefore, some security measures should be taken to mitigate potential threats.
Demonstrating Proof of Possession (DPoP) is a mechanism designed to restrict who can use an access or refresh token. With this mechanism, the authorization server issues a token that is bound to the requesting client, so that no one other than that specific client can use the access or refresh token. In other words, a token issued by using DPoP is no longer a bearer token.
Request a DPoP access token
The client using an access token with DPoP must prove that it is the legitimate recipient of the token. This is done using public key cryptography: the client must prove that it has the private key of the public/private key pair. But let's go in order to understand how DPoP works with a standard OAuth 2.0 flow.
For simplicity, we will use the Authorization Code flow, but the same applies to the other flows. The high-level steps are listed below:
- The user is redirected to the authorization server with a request to initiate the flow.
- The authorization server authenticates the user and redirects them back to the application with an authorization code.
- The client application generates a public/private key pair and creates a DPoP proof, which is a JWT containing the public key and the method and URI of the HTTP request where it will be used. This also binds the DPoP proof to a specific HTTP request.
- The client application sends the authorization code to the authorization server to request an access token. The HTTP request includes the DPoP proof in the
DPoPheader field. The following is an example of access token request with DPoP proof:
POST /token HTTP/1.1
- The authorization server validates the DPoP proof by checking the signature and the request details (HTTP method and URI). It then generates a hash of the client's public key (JWK thumbprint) and embeds it in the access token. For non-JWT access tokens, the JWK thumbprint can be checked through the introspection endpoint. Finally, the authorization server sends the access token with the JWK thumbprint to the client application.
Use a DPoP access token
When the client application needs to call a protected API, it performs the following steps:
- The client application creates a new DPoP proof bound to the HTTP request it's about to make.
- The client sends the access token in the
Authorizationheader field of the HTTP request using the
DPoPscheme. It also provides the DPoP proof in the
DPoPheader field. The following is an API call example with DPoP proof:
GET /protectedresource HTTP/1.1
Authorization: DPoP eyJhbGciOiJFUzI1NiIsInR5cCI6ImF0K0pXVCIsImNuZiI6eyJqa3QiOiJybW56aTJvSWNYW...
- In addition to the standard access token validation, the API also validates the DPoP proof to make sure that this request comes from the intended sender.
While using DPoP provides more security than the simple bearer token, this does not mean that there are no threats to DPoP access tokens. Take a look at the security considerations in the DPoP specification to learn more.
Step-Up Authentication Challenge Protocol
A second security enhancement to OAuth 2.0 has been introduced with the Step-Up Authentication Challenge Protocol specification, which has our Vittorio as its author along with Brian Campbell.
This specification adds Step-Up Authentication to OAuth 2.0-protected APIs to enforce stronger authentication requirements when a risky operation is requested by a client. In other words, when a client calls a critical API endpoint, the server checks that the access token meets specific authentication requirements, and if it's doesn't, it returns an error response to the client with directions on what is required.
The step-up authentication flow
Basically, the high-level flow has the following steps:
- The client sends a request to a critical API endpoint including the access token.
- The API endpoint extracts information about user authentication from the access token.
- If the user authentication information meets the authentication requirements for that endpoint, the request is processed. Otherwise, the API endpoint returns an error response that includes the authentication requirements.
- The client requests a new access token from the authorization server that meets the authentication requirements.
The authentication requirements
The specification defines two types of authentication requirements:
- Authentication Context Class Reference (ACR): This requirement indicates one or more specific authentication methods. For example, it can specify that Multi-Factor Authentication (MFA) is required.
- Maximum Authentication Age: This requirement specifies the elapsed time since the last active user authentication. An active user authentication occurs when the user is actively involved, for example by entering a username and password. An implicit authentication due to a still valid authenticated session is not considered an active user authentication.
These requirements are embedded in a JWT access token through the standard
auth_time claims. For non-JWT access tokens, the requirements can be verified through the introspection endpoint.
This article provided a high-level overview of the new specifications released in September 2023 to improve the security of OAuth 2.0. The DPoP specification defines a mechanism to bind an access token to the client application that requested it, overcoming the risks associated with bearer tokens. The Step-up Authentication Challenge Protocol defines a way to request more stringent authentication requirements when accessing a critical resource or requesting a risky operation from a client.