In DPoP, the prevention of token replay at a different endpoint (see
Section 2) is achieved through authentication of the server per [
RFC 6125] and the binding of the DPoP proof to a certain URI and HTTP method. However, DPoP has a somewhat different nature of protection than TLS-based methods such as OAuth Mutual TLS [
RFC 8705] or OAuth Token Binding [
TOKEN-BINDING] (see also Sections [
11.1] and [
11.7]). TLS-based mechanisms can leverage a tight integration between the TLS layer and the application layer to achieve strong message integrity, authenticity, and replay protection.
If an adversary is able to get hold of a DPoP proof JWT, the adversary could replay that token at the same endpoint (the HTTP endpoint and method are enforced via the respective claims in the JWTs). To limit this, servers
MUST only accept DPoP proofs for a limited time after their creation (preferably only for a relatively brief period on the order of seconds or minutes).
In the context of the target URI, servers can store the
jti value of each DPoP proof for the time window in which the respective DPoP proof JWT would be accepted to prevent multiple uses of the same DPoP proof. HTTP requests to the same URI for which the
jti value has been seen before would be declined. When strictly enforced, such a single-use check provides a very strong protection against DPoP proof replay, but it may not always be feasible in practice, e.g., when multiple servers behind a single endpoint have no shared state.
In order to guard against memory exhaustion attacks, a server that is tracking
jti values should reject DPoP proof JWTs with unnecessarily large
jti values or store only a hash thereof.
Note: To accommodate for clock offsets, the server
MAY accept DPoP proofs that carry an
iat time in the reasonably near future (on the order of seconds or minutes). Because clock skews between servers and clients may be large, servers
MAY limit DPoP proof lifetimes by using server-provided nonce values containing the time at the server rather than comparing the client-supplied
iat time to the time at the server. Nonces created in this way yield the same result even in the face of arbitrarily large clock skews.
Server-provided nonces are an effective means for further reducing the chances for successful DPoP proof replay. Unlike cryptographic nonces, it is acceptable for clients to use the same
nonce multiple times and for the server to accept the same nonce multiple times. As long as the
jti value is tracked and duplicates are rejected for the lifetime of the
nonce, there is no additional risk of token replay.
An attacker in control of the client can pre-generate DPoP proofs for specific endpoints arbitrarily far into the future by choosing the
iat value in the DPoP proof to be signed by the proof-of-possession key. Note that one such attacker is the person who is the legitimate user of the client. The user may pre-generate DPoP proofs to exfiltrate from the machine possessing the proof-of-possession key upon which they were generated and copy them to another machine that does not possess the key. For instance, a bank employee might pre-generate DPoP proofs on a bank computer and then copy them to another machine for use in the future, thereby bypassing bank audit controls. When DPoP proofs can be pre-generated and exfiltrated, all that is actually being proved in DPoP protocol interactions is possession of a DPoP proof -- not of the proof-of-possession key.
Use of server-provided nonce values that are not predictable by attackers can prevent this attack. By providing new nonce values at times of its choosing, the server can limit the lifetime of DPoP proofs, preventing pre-generated DPoP proofs from being used. When server-provided nonces are used, possession of the proof-of-possession key is being demonstrated -- not just possession of a DPoP proof.
The
ath claim limits the use of pre-generated DPoP proofs to the lifetime of the access token. Deployments that do not utilize the nonce mechanism
SHOULD NOT issue long-lived DPoP constrained access tokens, preferring instead to use short-lived access tokens and refresh tokens. Whilst an attacker could pre-generate DPoP proofs to use the refresh token to obtain a new access token, they would be unable to realistically pre-generate DPoP proofs to use a newly issued access token.
A server
MUST NOT accept any DPoP proofs without the
nonce claim when a DPoP nonce has been provided to the client.
If an adversary is able to run code in the client's execution context, the security of DPoP is no longer guaranteed. Common issues in web applications leading to the execution of untrusted code are XSS and remote code inclusion attacks.
If the private key used for DPoP is stored in such a way that it cannot be exported, e.g., in a hardware or software security module, the adversary cannot exfiltrate the key and use it to create arbitrary DPoP proofs. The adversary can, however, create new DPoP proofs as long as the client is online and uses these proofs (together with the respective tokens) either on the victim's device or on a device under the attacker's control to send arbitrary requests that will be accepted by servers.
To send requests even when the client is offline, an adversary can try to pre-compute DPoP proofs using timestamps in the future and exfiltrate these together with the access or refresh token.
An adversary might further try to associate tokens issued from the token endpoint with a key pair under the adversary's control. One way to achieve this is to modify existing code, e.g., by replacing cryptographic APIs. Another way is to launch a new authorization grant between the client and the authorization server in an iframe. This grant needs to be "silent", i.e., not require interaction with the user. With code running in the client's origin, the adversary has access to the resulting authorization code and can use it to associate their own DPoP keys with the tokens returned from the token endpoint. The adversary is then able to use the resulting tokens on their own device even if the client is offline.
Therefore, protecting clients against the execution of untrusted code is extremely important even if DPoP is used. Besides secure coding practices, Content Security Policy [
W3C.CSP] can be used as a second layer of defense against XSS.
Servers accepting signed DPoP proof JWTs
MUST verify that the
typ field is
dpop+jwt in the headers of the JWTs to ensure that adversaries cannot use JWTs created for other purposes.
Implementers
MUST ensure that only asymmetric digital signature algorithms (such as
ES256) that are deemed secure can be used for signing DPoP proofs. In particular, the algorithm
none MUST NOT be allowed.
DPoP does not ensure the integrity of the payload or headers of requests. The DPoP proof only contains claims for the HTTP URI and method, but not the message body or general request headers, for example.
This is an intentional design decision intended to keep DPoP simple to use, but as described, it makes DPoP potentially susceptible to replay attacks where an attacker is able to modify message contents and headers. In many setups, the message integrity and confidentiality provided by TLS is sufficient to provide a good level of protection.
Note: While signatures covering other parts of requests are out of the scope of this specification, additional information to be signed can be added into DPoP proofs.
The binding of the access token to the DPoP public key, as specified in
Section 6, uses a cryptographic hash of the JWK representation of the public key. It relies on the hash function having sufficient second-preimage resistance so as to make it computationally infeasible to find or create another key that produces to the same hash output value. The SHA-256 hash function was used because it meets the aforementioned requirement while being widely available.
Similarly, the binding of the DPoP proof to the access token uses a hash of that access token as the value of the
ath claim in the DPoP proof (see
Section 4.2). This relies on the value of the hash being sufficiently unique so as to reliably identify the access token. The collision resistance of SHA-256 meets that requirement.
Cryptographic binding of the authorization code to the DPoP public key is specified in
Section 10. This binding prevents attacks in which the attacker captures the authorization code and creates a DPoP proof using a proof-of-possession key other than the one held by the client and redeems the authorization code using that DPoP proof. By ensuring end to end that only the client's DPoP key can be used, this prevents captured authorization codes from being exfiltrated and used at locations other than the one to which the authorization code was issued.
Authorization codes can, for instance, be harvested by attackers from places where the HTTP messages containing them are logged. Even when efforts are made to make authorization codes one-time-use, in practice, there is often a time window during which attackers can replay them. For instance, when authorization servers are implemented as scalable replicated services, some replicas may temporarily not yet have the information needed to prevent replay. DPoP binding of the authorization code solves these problems.
If an authorization server does not (or cannot) strictly enforce the single-use limitation for authorization codes and an attacker can access the authorization code (and if PKCE is used, the
code_verifier), the attacker can create a forged token request, binding the resulting token to an attacker-controlled key. For example, using XSS, attackers might obtain access to the authorization code and PKCE parameters. Use of the
dpop_jkt parameter prevents this attack.
The binding of the authorization code to the DPoP public key uses a JWK Thumbprint of the public key, just as the access token binding does. The same JWK Thumbprint considerations apply.
The
jkt confirmation method member, the
ath JWT claim, and the
dpop_jkt authorization request parameter defined herein all use the output of the SHA-256 hash function as their value. The use of a single hash function by this specification was intentional and aimed at simplicity and avoidance of potential security and interoperability issues arising from common mistakes implementing and deploying parameterized algorithm agility schemes. However, the use of a different hash function is not precluded if future circumstances change and make SHA-256 insufficient for the requirements of this specification. Should that need arise, it is expected that a short specification will be produced that updates this one. Using the output of an appropriate hash function as the value, that specification will likely define a new confirmation method member, a new JWT claim, and a new authorization request parameter. These items will be used in place of, or alongside, their respective counterparts in the same message structures and flows of the larger protocol defined by this specification.
In cases where DPoP is used with client authentication, it is only bound to authentication by being coincident in the same TLS tunnel. Since the DPoP proof is not directly bound to the authentication cryptographically, it's possible that the authentication or the DPoP messages were copied into the tunnel. While including the URI in the DPoP can partially mitigate some of this risk, modifying the authentication mechanism to provide cryptographic binding between authentication and DPoP could provide better protection. However, providing additional binding with authentication through the modification of authentication mechanisms or other means is beyond the scope of this specification.