| rfc9449.original | rfc9449.txt | |||
|---|---|---|---|---|
| Web Authorization Protocol D. Fett | Internet Engineering Task Force (IETF) D. Fett | |||
| Internet-Draft Authlete | Request for Comments: 9449 Authlete | |||
| Intended status: Standards Track B. Campbell | Category: Standards Track B. Campbell | |||
| Expires: 15 October 2023 Ping Identity | ISSN: 2070-1721 Ping Identity | |||
| J. Bradley | J. Bradley | |||
| Yubico | Yubico | |||
| T. Lodderstedt | T. Lodderstedt | |||
| yes.com | Tuconic | |||
| M. Jones | M. Jones | |||
| independent | Self-Issued Consulting | |||
| D. Waite | D. Waite | |||
| Ping Identity | Ping Identity | |||
| 13 April 2023 | September 2023 | |||
| OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer | OAuth 2.0 Demonstrating Proof of Possession (DPoP) | |||
| (DPoP) | ||||
| draft-ietf-oauth-dpop-16 | ||||
| Abstract | Abstract | |||
| This document describes a mechanism for sender-constraining OAuth 2.0 | This document describes a mechanism for sender-constraining OAuth 2.0 | |||
| tokens via a proof-of-possession mechanism on the application level. | tokens via a proof-of-possession mechanism on the application level. | |||
| This mechanism allows for the detection of replay attacks with access | This mechanism allows for the detection of replay attacks with access | |||
| and refresh tokens. | and refresh tokens. | |||
| Status of This Memo | Status of This Memo | |||
| This Internet-Draft is submitted in full conformance with the | This is an Internet Standards Track document. | |||
| provisions of BCP 78 and BCP 79. | ||||
| Internet-Drafts are working documents of the Internet Engineering | ||||
| Task Force (IETF). Note that other groups may also distribute | ||||
| working documents as Internet-Drafts. The list of current Internet- | ||||
| Drafts is at https://datatracker.ietf.org/drafts/current/. | ||||
| Internet-Drafts are draft documents valid for a maximum of six months | This document is a product of the Internet Engineering Task Force | |||
| and may be updated, replaced, or obsoleted by other documents at any | (IETF). It represents the consensus of the IETF community. It has | |||
| time. It is inappropriate to use Internet-Drafts as reference | received public review and has been approved for publication by the | |||
| material or to cite them other than as "work in progress." | Internet Engineering Steering Group (IESG). Further information on | |||
| Internet Standards is available in Section 2 of RFC 7841. | ||||
| This Internet-Draft will expire on 15 October 2023. | Information about the current status of this document, any errata, | |||
| and how to provide feedback on it may be obtained at | ||||
| https://www.rfc-editor.org/info/rfc9449. | ||||
| Copyright Notice | Copyright Notice | |||
| Copyright (c) 2023 IETF Trust and the persons identified as the | Copyright (c) 2023 IETF Trust and the persons identified as the | |||
| document authors. All rights reserved. | document authors. All rights reserved. | |||
| This document is subject to BCP 78 and the IETF Trust's Legal | This document is subject to BCP 78 and the IETF Trust's Legal | |||
| Provisions Relating to IETF Documents (https://trustee.ietf.org/ | Provisions Relating to IETF Documents | |||
| license-info) in effect on the date of publication of this document. | (https://trustee.ietf.org/license-info) in effect on the date of | |||
| Please review these documents carefully, as they describe your rights | publication of this document. Please review these documents | |||
| and restrictions with respect to this document. Code Components | carefully, as they describe your rights and restrictions with respect | |||
| extracted from this document must include Revised BSD License text as | to this document. Code Components extracted from this document must | |||
| described in Section 4.e of the Trust Legal Provisions and are | include Revised BSD License text as described in Section 4.e of the | |||
| provided without warranty as described in the Revised BSD License. | Trust Legal Provisions and are provided without warranty as described | |||
| in the Revised BSD License. | ||||
| Table of Contents | Table of Contents | |||
| 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 | 1. Introduction | |||
| 1.1. Conventions and Terminology . . . . . . . . . . . . . . . 4 | 1.1. Conventions and Terminology | |||
| 2. Objectives . . . . . . . . . . . . . . . . . . . . . . . . . 5 | 2. Objectives | |||
| 3. Concept . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 | 3. Concept | |||
| 4. DPoP Proof JWTs . . . . . . . . . . . . . . . . . . . . . . . 8 | 4. DPoP Proof JWTs | |||
| 4.1. The DPoP HTTP Header . . . . . . . . . . . . . . . . . . 8 | 4.1. The DPoP HTTP Header | |||
| 4.2. DPoP Proof JWT Syntax . . . . . . . . . . . . . . . . . . 9 | 4.2. DPoP Proof JWT Syntax | |||
| 4.3. Checking DPoP Proofs . . . . . . . . . . . . . . . . . . 11 | 4.3. Checking DPoP Proofs | |||
| 5. DPoP Access Token Request . . . . . . . . . . . . . . . . . . 12 | 5. DPoP Access Token Request | |||
| 5.1. Authorization Server Metadata . . . . . . . . . . . . . . 15 | 5.1. Authorization Server Metadata | |||
| 5.2. Client Registration Metadata . . . . . . . . . . . . . . 15 | 5.2. Client Registration Metadata | |||
| 6. Public Key Confirmation . . . . . . . . . . . . . . . . . . . 16 | 6. Public Key Confirmation | |||
| 6.1. JWK Thumbprint Confirmation Method . . . . . . . . . . . 16 | 6.1. JWK Thumbprint Confirmation Method | |||
| 6.2. JWK Thumbprint Confirmation Method in Token | 6.2. JWK Thumbprint Confirmation Method in Token Introspection | |||
| Introspection . . . . . . . . . . . . . . . . . . . . . . 17 | 7. Protected Resource Access | |||
| 7. Protected Resource Access . . . . . . . . . . . . . . . . . . 18 | 7.1. The DPoP Authentication Scheme | |||
| 7.1. The DPoP Authentication Scheme . . . . . . . . . . . . . 19 | 7.2. Compatibility with the Bearer Authentication Scheme | |||
| 7.2. Compatibility with the Bearer Authentication Scheme . . . 22 | 7.3. Client Considerations | |||
| 7.3. Client Considerations . . . . . . . . . . . . . . . . . . 24 | 8. Authorization Server-Provided Nonce | |||
| 8. Authorization Server-Provided Nonce . . . . . . . . . . . . . 24 | 8.1. Nonce Syntax | |||
| 8.1. Nonce Syntax . . . . . . . . . . . . . . . . . . . . . . 26 | 8.2. Providing a New Nonce Value | |||
| 8.2. Providing a New Nonce Value . . . . . . . . . . . . . . . 26 | 9. Resource Server-Provided Nonce | |||
| 9. Resource Server-Provided Nonce . . . . . . . . . . . . . . . 27 | 10. Authorization Code Binding to a DPoP Key | |||
| 10. Authorization Code Binding to DPoP Key . . . . . . . . . . . 28 | 10.1. DPoP with Pushed Authorization Requests | |||
| 10.1. DPoP with Pushed Authorization Requests . . . . . . . . 28 | 11. Security Considerations | |||
| 11. Security Considerations . . . . . . . . . . . . . . . . . . . 29 | 11.1. DPoP Proof Replay | |||
| 11.1. DPoP Proof Replay . . . . . . . . . . . . . . . . . . . 29 | 11.2. DPoP Proof Pre-generation | |||
| 11.2. DPoP Proof Pre-Generation . . . . . . . . . . . . . . . 30 | 11.3. DPoP Nonce Downgrade | |||
| 11.3. DPoP Nonce Downgrade . . . . . . . . . . . . . . . . . . 31 | 11.4. Untrusted Code in the Client Context | |||
| 11.4. Untrusted Code in the Client Context . . . . . . . . . . 31 | 11.5. Signed JWT Swapping | |||
| 11.5. Signed JWT Swapping . . . . . . . . . . . . . . . . . . 32 | 11.6. Signature Algorithms | |||
| 11.6. Signature Algorithms . . . . . . . . . . . . . . . . . . 32 | 11.7. Request Integrity | |||
| 11.7. Request Integrity . . . . . . . . . . . . . . . . . . . 32 | 11.8. Access Token and Public Key Binding | |||
| 11.8. Access Token and Public Key Binding . . . . . . . . . . 33 | 11.9. Authorization Code and Public Key Binding | |||
| 11.9. Authorization Code and Public Key Binding . . . . . . . 33 | 11.10. Hash Algorithm Agility | |||
| 11.10. Hash Algorithm Agility . . . . . . . . . . . . . . . . . 34 | 11.11. Binding to Client Identity | |||
| 11.11. Binding to Client Identity . . . . . . . . . . . . . . . 34 | 12. IANA Considerations | |||
| 12.1. OAuth Access Token Types Registration | ||||
| 12. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 34 | 12.2. OAuth Extensions Error Registration | |||
| 12.1. OAuth Access Token Type Registration . . . . . . . . . . 34 | 12.3. OAuth Parameters Registration | |||
| 12.2. OAuth Extensions Error Registration . . . . . . . . . . 35 | 12.4. HTTP Authentication Schemes Registration | |||
| 12.3. OAuth Parameters Registration . . . . . . . . . . . . . 35 | 12.5. Media Type Registration | |||
| 12.4. HTTP Authentication Scheme Registration . . . . . . . . 35 | 12.6. JWT Confirmation Methods Registration | |||
| 12.5. Media Type Registration . . . . . . . . . . . . . . . . 36 | 12.7. JSON Web Token Claims Registration | |||
| 12.6. JWT Confirmation Methods Registration . . . . . . . . . 36 | 12.7.1. "nonce" Registration Update | |||
| 12.7. JSON Web Token Claims Registration . . . . . . . . . . . 36 | 12.8. Hypertext Transfer Protocol (HTTP) Field Name Registration | |||
| 12.7.1. "nonce" Registry Update . . . . . . . . . . . . . . 37 | 12.9. OAuth Authorization Server Metadata Registration | |||
| 12.8. HTTP Message Header Field Names Registration . . . . . . 38 | 12.10. OAuth Dynamic Client Registration Metadata | |||
| 12.9. OAuth Authorization Server Metadata Registration . . . . 38 | 13. References | |||
| 12.10. OAuth Dynamic Client Registration Metadata . . . . . . . 38 | 13.1. Normative References | |||
| 13. Normative References . . . . . . . . . . . . . . . . . . . . 38 | 13.2. Informative References | |||
| 14. Informative References . . . . . . . . . . . . . . . . . . . 40 | Acknowledgements | |||
| Appendix A. Acknowledgements . . . . . . . . . . . . . . . . . . 43 | Authors' Addresses | |||
| Appendix B. Document History . . . . . . . . . . . . . . . . . . 44 | ||||
| Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 48 | ||||
| 1. Introduction | 1. Introduction | |||
| DPoP (for Demonstrating Proof-of-Possession at the Application Layer) | Demonstrating Proof of Possession (DPoP) is an application-level | |||
| is an application-level mechanism for sender-constraining OAuth | mechanism for sender-constraining OAuth [RFC6749] access and refresh | |||
| [RFC6749] access and refresh tokens. It enables a client to prove | tokens. It enables a client to prove the possession of a public/ | |||
| the possession of a public/private key pair by including a DPoP | private key pair by including a DPoP header in an HTTP request. The | |||
| header in an HTTP request. The value of the header is a JSON Web | value of the header is a JSON Web Token (JWT) [RFC7519] that enables | |||
| Token (JWT) [RFC7519] that enables the authorization server to bind | the authorization server to bind issued tokens to the public part of | |||
| issued tokens to the public part of a client's key pair. Recipients | a client's key pair. Recipients of such tokens are then able to | |||
| of such tokens are then able to verify the binding of the token to | verify the binding of the token to the key pair that the client has | |||
| the key pair that the client has demonstrated that it holds via the | demonstrated that it holds via the DPoP header, thereby providing | |||
| DPoP header, thereby providing some assurance that the client | some assurance that the client presenting the token also possesses | |||
| presenting the token also possesses the private key. In other words, | the private key. In other words, the legitimate presenter of the | |||
| the legitimate presenter of the token is constrained to be the sender | token is constrained to be the sender that holds and proves | |||
| that holds and can prove possession of the private part of the key | possession of the private part of the key pair. | |||
| pair. | ||||
| The mechanism specified herein can be used in cases where other | The mechanism specified herein can be used in cases where other | |||
| methods of sender-constraining tokens that utilize elements of the | methods of sender-constraining tokens that utilize elements of the | |||
| underlying secure transport layer, such as [RFC8705] or | underlying secure transport layer, such as [RFC8705] or | |||
| [I-D.ietf-oauth-token-binding], are not available or desirable. For | [TOKEN-BINDING], are not available or desirable. For example, due to | |||
| example, due to a sub-par user experience of TLS client | a sub-par user experience of TLS client authentication in user agents | |||
| authentication in user agents and a lack of support for HTTP token | and a lack of support for HTTP token binding, neither mechanism can | |||
| binding, neither mechanism can be used if an OAuth client is an | be used if an OAuth client is an application that is dynamically | |||
| application that is dynamically downloaded and executed in a web | downloaded and executed in a web browser (sometimes referred to as a | |||
| browser (sometimes referred to as a "single-page application"). | "single-page application"). Additionally, applications that are | |||
| Applications installed and run directly on a user's device are | installed and run directly on a user's device are well positioned to | |||
| another example well positioned to benefit from DPoP-bound tokens to | benefit from DPoP-bound tokens that guard against the misuse of | |||
| guard against misuse of tokens by a compromised or malicious | tokens by a compromised or malicious resource. Such applications | |||
| resource. Such applications often have dedicated protected storage | often have dedicated protected storage for cryptographic keys. | |||
| for cryptographic keys. | ||||
| DPoP can be used to sender-constrain access tokens regardless of the | DPoP can be used to sender-constrain access tokens regardless of the | |||
| client authentication method employed, but DPoP itself is not used | client authentication method employed, but DPoP itself is not used | |||
| for client authentication. DPoP can also be used to sender-constrain | for client authentication. DPoP can also be used to sender-constrain | |||
| refresh tokens issued to public clients (those without authentication | refresh tokens issued to public clients (those without authentication | |||
| credentials associated with the client_id). | credentials associated with the client_id). | |||
| 1.1. Conventions and Terminology | 1.1. Conventions and Terminology | |||
| The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", | |||
| "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and | "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and | |||
| "OPTIONAL" in this document are to be interpreted as described in BCP | "OPTIONAL" in this document are to be interpreted as described in | |||
| 14 [RFC2119] [RFC8174] when, and only when, they appear in all | BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all | |||
| capitals, as shown here. | capitals, as shown here. | |||
| This specification uses the Augmented Backus-Naur Form (ABNF) | This specification uses the Augmented Backus-Naur Form (ABNF) | |||
| notation of [RFC5234]. | notation of [RFC5234]. | |||
| This specification uses the terms "access token", "refresh token", | This specification uses the terms "access token", "refresh token", | |||
| "authorization server", "resource server", "authorization endpoint", | "authorization server", "resource server", "authorization endpoint", | |||
| "authorization request", "authorization response", "token endpoint", | "authorization request", "authorization response", "token endpoint", | |||
| "grant type", "access token request", "access token response", | "grant type", "access token request", "access token response", | |||
| "client", "public client", and "confidential client" defined by The | "client", "public client", and "confidential client" defined by "The | |||
| OAuth 2.0 Authorization Framework [RFC6749]. | OAuth 2.0 Authorization Framework" [RFC6749]. | |||
| The terms "request", "response", "header field", and "target URI" are | The terms "request", "response", "header field", and "target URI" are | |||
| imported from [RFC9110]. | imported from [RFC9110]. | |||
| The terms "JOSE" and "JOSE header" are imported from [RFC7515]. | The terms "JOSE" and "JOSE Header" are imported from [RFC7515]. | |||
| This document contains non-normative examples of partial and complete | This document contains non-normative examples of partial and complete | |||
| HTTP messages. Some examples use a single trailing backslash to | HTTP messages. Some examples use a single trailing backslash to | |||
| indicate line wrapping for long values, as per [RFC8792]. The | indicate line wrapping for long values, as per [RFC8792]. The | |||
| character and leading spaces on wrapped lines are not part of the | character and leading spaces on wrapped lines are not part of the | |||
| value. | value. | |||
| 2. Objectives | 2. Objectives | |||
| The primary aim of DPoP is to prevent unauthorized or illegitimate | The primary aim of DPoP is to prevent unauthorized or illegitimate | |||
| skipping to change at page 5, line 27 ¶ | skipping to change at line 191 ¶ | |||
| This constrains the legitimate sender of the token to only the party | This constrains the legitimate sender of the token to only the party | |||
| with access to the private key and gives the server receiving the | with access to the private key and gives the server receiving the | |||
| token added assurances that the sender is legitimately authorized to | token added assurances that the sender is legitimately authorized to | |||
| use it. | use it. | |||
| Access tokens that are sender-constrained via DPoP thus stand in | Access tokens that are sender-constrained via DPoP thus stand in | |||
| contrast to the typical bearer token, which can be used by any party | contrast to the typical bearer token, which can be used by any party | |||
| in possession of such a token. Although protections generally exist | in possession of such a token. Although protections generally exist | |||
| to prevent unintended disclosure of bearer tokens, unforeseen vectors | to prevent unintended disclosure of bearer tokens, unforeseen vectors | |||
| for leakage have occurred due to vulnerabilities and implementation | for leakage have occurred due to vulnerabilities and implementation | |||
| issues in other layers in the protocol or software stack (CRIME | issues in other layers in the protocol or software stack (see, e.g., | |||
| [CRIME], BREACH [BREACH], Heartbleed [Heartbleed], and the Cloudflare | Compression Ratio Info-leak Made Easy (CRIME) [CRIME], Browser | |||
| parser bug [Cloudbleed] are some examples). There have also been | Reconnaissance and Exfiltration via Adaptive Compression of Hypertext | |||
| numerous published token theft attacks on OAuth implementations | (BREACH) [BREACH], Heartbleed [Heartbleed], and the Cloudflare parser | |||
| themselves ([GitHub.Tokens] as just one high profile example). DPoP | bug [Cloudbleed]). There have also been numerous published token | |||
| provides a general defense in depth against the impact of | theft attacks on OAuth implementations themselves ([GitHub.Tokens] is | |||
| unanticipated token leakage. DPoP is not, however, a substitute for | just one high-profile example). DPoP provides a general defense in | |||
| a secure transport and MUST always be used in conjunction with HTTPS. | depth against the impact of unanticipated token leakage. DPoP is | |||
| not, however, a substitute for a secure transport and MUST always be | ||||
| used in conjunction with HTTPS. | ||||
| The very nature of the typical OAuth protocol interaction | The very nature of the typical OAuth protocol interaction | |||
| necessitates that the client discloses the access token to the | necessitates that the client discloses the access token to the | |||
| protected resources that it accesses. The attacker model in | protected resources that it accesses. The attacker model in | |||
| [I-D.ietf-oauth-security-topics] describes cases where a protected | [SECURITY-TOPICS] describes cases where a protected resource might be | |||
| resource might be counterfeit, malicious or compromised and plays | counterfeit, malicious, or compromised and plays received tokens | |||
| received tokens against other protected resources to gain | against other protected resources to gain unauthorized access. | |||
| unauthorized access. Audience restricted access tokens (e.g., using | Audience-restricted access tokens (e.g., using the JWT [RFC7519] aud | |||
| the JWT [RFC7519] aud claim) can prevent such misuse, however, doing | claim) can prevent such misuse. However, doing so in practice has | |||
| so in practice has proven to be prohibitively cumbersome for many | proven to be prohibitively cumbersome for many deployments (despite | |||
| deployments (even despite extensions such as [RFC8707]). Sender- | extensions such as [RFC8707]). Sender-constraining access tokens is | |||
| constraining access tokens is a more robust and straightforward | a more robust and straightforward mechanism to prevent such token | |||
| mechanism to prevent such token replay at a different endpoint and | replay at a different endpoint, and DPoP is an accessible | |||
| DPoP is an accessible application layer means of doing so. | application-layer means of doing so. | |||
| Due to the potential for cross-site scripting (XSS), browser-based | Due to the potential for cross-site scripting (XSS), browser-based | |||
| OAuth clients bring to bear added considerations with respect to | OAuth clients bring to bear added considerations with respect to | |||
| protecting tokens. The most straightforward XSS-based attack is for | protecting tokens. The most straightforward XSS-based attack is for | |||
| an attacker to exfiltrate a token and use it themselves completely | an attacker to exfiltrate a token and use it themselves completely | |||
| independent of the legitimate client. A stolen access token is used | independent of the legitimate client. A stolen access token is used | |||
| for protected resource access and a stolen refresh token for | for protected resource access, and a stolen refresh token is used for | |||
| obtaining new access tokens. If the private key is non-extractable | obtaining new access tokens. If the private key is non-extractable | |||
| (as is possible with [W3C.WebCryptoAPI]), DPoP renders exfiltrated | (as is possible with [W3C.WebCryptoAPI]), DPoP renders exfiltrated | |||
| tokens alone unusable. | tokens alone unusable. | |||
| XSS vulnerabilities also allow an attacker to execute code in the | XSS vulnerabilities also allow an attacker to execute code in the | |||
| context of the browser-based client application and maliciously use a | context of the browser-based client application and maliciously use a | |||
| token indirectly through the client. That execution context has | token indirectly through the client. That execution context has | |||
| access to utilize the signing key and thus can produce DPoP proofs to | access to utilize the signing key; thus, it can produce DPoP proofs | |||
| use in conjunction with the token. At this application layer there | to use in conjunction with the token. At this application layer, | |||
| is most likely no feasible defense against this threat except | there is most likely no feasible defense against this threat except | |||
| generally preventing XSS, therefore it is considered out of scope for | generally preventing XSS; therefore, it is considered out of scope | |||
| DPoP. | for DPoP. | |||
| Malicious XSS code executed in the context of the browser-based | Malicious XSS code executed in the context of the browser-based | |||
| client application is also in a position to create DPoP proofs with | client application is also in a position to create DPoP proofs with | |||
| timestamp values in the future and exfiltrate them in conjunction | timestamp values in the future and exfiltrate them in conjunction | |||
| with a token. These stolen artifacts can later be used independent | with a token. These stolen artifacts can later be used independent | |||
| of the client application to access protected resources. To prevent | of the client application to access protected resources. To prevent | |||
| this, servers can optionally require clients to include a server- | this, servers can optionally require clients to include a server- | |||
| chosen value into the proof that cannot be predicted by an attacker | chosen value into the proof that cannot be predicted by an attacker | |||
| (nonce). In the absence of the optional nonce, the impact of pre- | (nonce). In the absence of the optional nonce, the impact of pre- | |||
| computed DPoP proofs is limited somewhat by the proof being bound to | computed DPoP proofs is limited somewhat by the proof being bound to | |||
| an access token on protected resource access. Because a proof | an access token on protected resource access. Because a proof | |||
| covering an access token that does not yet exist cannot feasibly be | covering an access token that does not yet exist cannot feasibly be | |||
| created, access tokens obtained with an exfiltrated refresh token and | created, access tokens obtained with an exfiltrated refresh token and | |||
| pre-computed proofs will be unusable. | pre-computed proofs will be unusable. | |||
| Additional security considerations are discussed in Section 11. | Additional security considerations are discussed in Section 11. | |||
| 3. Concept | 3. Concept | |||
| The main data structure introduced by this specification is a DPoP | The main data structure introduced by this specification is a DPoP | |||
| proof JWT, described in detail below, which is sent as a header in an | proof JWT that is sent as a header in an HTTP request, as described | |||
| HTTP request. A client uses a DPoP proof JWT to prove the possession | in detail below. A client uses a DPoP proof JWT to prove the | |||
| of a private key corresponding to a certain public key. | possession of a private key corresponding to a certain public key. | |||
| Roughly speaking, a DPoP proof is a signature over some data of the | Roughly speaking, a DPoP proof is a signature over: | |||
| HTTP request to which it is attached, a timestamp, a unique | ||||
| identifier, an optional server-provided nonce, and a hash of the | * some data of the HTTP request to which it is attached, | |||
| associated access token when an access token is present within the | ||||
| request. | * a timestamp, | |||
| * a unique identifier, | ||||
| * an optional server-provided nonce, and | ||||
| * a hash of the associated access token when an access token is | ||||
| present within the request. | ||||
| +--------+ +---------------+ | +--------+ +---------------+ | |||
| | |--(A)-- Token Request ------------------->| | | | |--(A)-- Token Request ------------------->| | | |||
| | Client | (DPoP Proof) | Authorization | | | Client | (DPoP Proof) | Authorization | | |||
| | | | Server | | | | | Server | | |||
| | |<-(B)-- DPoP-bound Access Token ----------| | | | |<-(B)-- DPoP-Bound Access Token ----------| | | |||
| | | (token_type=DPoP) +---------------+ | | | (token_type=DPoP) +---------------+ | |||
| | | | | | | |||
| | | | | | | |||
| | | +---------------+ | | | +---------------+ | |||
| | |--(C)-- DPoP-bound Access Token --------->| | | | |--(C)-- DPoP-Bound Access Token --------->| | | |||
| | | (DPoP Proof) | Resource | | | | (DPoP Proof) | Resource | | |||
| | | | Server | | | | | Server | | |||
| | |<-(D)-- Protected Resource ---------------| | | | |<-(D)-- Protected Resource ---------------| | | |||
| | | +---------------+ | | | +---------------+ | |||
| +--------+ | +--------+ | |||
| Figure 1: Basic DPoP Flow | Figure 1: Basic DPoP Flow | |||
| The basic steps of an OAuth flow with DPoP (without the optional | The basic steps of an OAuth flow with DPoP (without the optional | |||
| nonce) are shown in Figure 1: | nonce) are shown in Figure 1. | |||
| * (A) In the Token Request, the client sends an authorization grant | A. In the token request, the client sends an authorization grant | |||
| (e.g., an authorization code, refresh token, etc.) | (e.g., an authorization code, refresh token, etc.) to the | |||
| to the authorization server in order to obtain an access token | authorization server in order to obtain an access token (and | |||
| (and potentially a refresh token). The client attaches a DPoP | potentially a refresh token). The client attaches a DPoP proof | |||
| proof to the request in an HTTP header. | to the request in an HTTP header. | |||
| * (B) The authorization server binds (sender-constrains) the access | ||||
| token to the public key claimed by the client in the DPoP proof; | B. The authorization server binds (sender-constrains) the access | |||
| that is, the access token cannot be used without proving | token to the public key claimed by the client in the DPoP proof; | |||
| possession of the respective private key. If a refresh token is | that is, the access token cannot be used without proving | |||
| issued to a public client, it too is bound to the public key of | possession of the respective private key. If a refresh token is | |||
| the DPoP proof. | issued to a public client, it is also bound to the public key of | |||
| * (C) To use the access token, the client has to prove possession of | the DPoP proof. | |||
| the private key by, again, adding a header to the request that | ||||
| carries a DPoP proof for that request. The resource server needs | C. To use the access token, the client has to prove possession of | |||
| to receive information about the public key to which the access | the private key by, again, adding a header to the request that | |||
| token is bound. This information may be encoded directly into the | carries a DPoP proof for that request. The resource server needs | |||
| access token (for JWT structured access tokens) or provided via | to receive information about the public key to which the access | |||
| token introspection endpoint (not shown). The resource server | token is bound. This information may be encoded directly into | |||
| verifies that the public key to which the access token is bound | the access token (for JWT-structured access tokens) or provided | |||
| matches the public key of the DPoP proof. It also verifies that | via token introspection endpoint (not shown). The resource | |||
| the access token hash in the DPoP proof matches the access token | server verifies that the public key to which the access token is | |||
| presented in the request. | bound matches the public key of the DPoP proof. It also verifies | |||
| * (D) The resource server refuses to serve the request if the | that the access token hash in the DPoP proof matches the access | |||
| signature check fails or the data in the DPoP proof is wrong, | token presented in the request. | |||
| e.g., the target URI does not match the URI claim in the DPoP | ||||
| proof JWT. The access token itself, of course, must also be valid | D. The resource server refuses to serve the request if the signature | |||
| in all other respects. | check fails or if the data in the DPoP proof is wrong, e.g., the | |||
| target URI does not match the URI claim in the DPoP proof JWT. | ||||
| The access token itself, of course, must also be valid in all | ||||
| other respects. | ||||
| The DPoP mechanism presented herein is not a client authentication | The DPoP mechanism presented herein is not a client authentication | |||
| method. In fact, a primary use case of DPoP is for public clients | method. In fact, a primary use case of DPoP is for public clients | |||
| (e.g., single page applications and applications on a user's device) | (e.g., single-page applications and applications on a user's device) | |||
| that do not use client authentication. Nonetheless, DPoP is designed | that do not use client authentication. Nonetheless, DPoP is designed | |||
| such that it is compatible with private_key_jwt and all other client | to be compatible with private_key_jwt and all other client | |||
| authentication methods. | authentication methods. | |||
| DPoP does not directly ensure message integrity but relies on the TLS | DPoP does not directly ensure message integrity, but it relies on the | |||
| layer for that purpose. See Section 11 for details. | TLS layer for that purpose. See Section 11 for details. | |||
| 4. DPoP Proof JWTs | 4. DPoP Proof JWTs | |||
| DPoP introduces the concept of a DPoP proof, which is a JWT created | DPoP introduces the concept of a DPoP proof, which is a JWT created | |||
| by the client and sent with an HTTP request using the DPoP header | by the client and sent with an HTTP request using the DPoP header | |||
| field. Each HTTP request requires a unique DPoP proof. | field. Each HTTP request requires a unique DPoP proof. | |||
| A valid DPoP proof demonstrates to the server that the client holds | A valid DPoP proof demonstrates to the server that the client holds | |||
| the private key that was used to sign the DPoP proof JWT. This | the private key that was used to sign the DPoP proof JWT. This | |||
| enables authorization servers to bind issued tokens to the | enables authorization servers to bind issued tokens to the | |||
| corresponding public key (as described in Section 5) and for resource | corresponding public key (as described in Section 5) and enables | |||
| servers to verify the key-binding of tokens that it receives (see | resource servers to verify the key-binding of tokens that it receives | |||
| Section 7.1), which prevents said tokens from being used by any | (see Section 7.1), which prevents said tokens from being used by any | |||
| entity that does not have access to the private key. | entity that does not have access to the private key. | |||
| The DPoP proof demonstrates possession of a key and, by itself, is | The DPoP proof demonstrates possession of a key and, by itself, is | |||
| not an authentication or access control mechanism. When presented in | not an authentication or access control mechanism. When presented in | |||
| conjunction with a key-bound access token as described in | conjunction with a key-bound access token as described in | |||
| Section 7.1, the DPoP proof provides additional assurance about the | Section 7.1, the DPoP proof provides additional assurance about the | |||
| legitimacy of the client to present the access token. However, a | legitimacy of the client to present the access token. However, a | |||
| valid DPoP proof JWT is not sufficient alone to make access control | valid DPoP proof JWT is not sufficient alone to make access control | |||
| decisions. | decisions. | |||
| 4.1. The DPoP HTTP Header | 4.1. The DPoP HTTP Header | |||
| A DPoP proof is included in an HTTP request using the following | A DPoP proof is included in an HTTP request using the following | |||
| request header field. | request header field. | |||
| DPoP A JWT that adheres to the structure and syntax of Section 4.2. | DPoP: A JWT that adheres to the structure and syntax of Section 4.2. | |||
| Figure 2 shows an example DPoP HTTP header field (with '\' line | Figure 2 shows an example DPoP HTTP header field. The example uses | |||
| wrapping per RFC 8792). | "\" line wrapping per [RFC8792]. | |||
| DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ | DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ | |||
| VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ | VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ | |||
| nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ | nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ | |||
| QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ | QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ | |||
| oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ | oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ | |||
| WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\ | WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\ | |||
| 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg | 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg | |||
| Figure 2: Example DPoP header | Figure 2: Example DPoP Header | |||
| Note that per [RFC9110] header field names are case-insensitive; so | Note that per [RFC9110], header field names are case insensitive; | |||
| DPoP, DPOP, dpop, etc., are all valid and equivalent header field | thus, DPoP, DPOP, dpop, etc., are all valid and equivalent header | |||
| names. Case is significant in the header field value, however. | field names. However, case is significant in the header field value. | |||
| The DPoP HTTP header field value uses the token68 syntax defined in | The DPoP HTTP header field value uses the token68 syntax defined in | |||
| Section 11.2 of [RFC9110] (repeated below in Figure 3 for ease of | Section 11.2 of [RFC9110] and is repeated below in Figure 3 for ease | |||
| reference). | of reference. | |||
| DPoP = token68 | DPoP = token68 | |||
| token68 = 1*( ALPHA / DIGIT / | token68 = 1*( ALPHA / DIGIT / | |||
| "-" / "." / "_" / "~" / "+" / "/" ) *"=" | "-" / "." / "_" / "~" / "+" / "/" ) *"=" | |||
| Figure 3: DPoP header field ABNF | Figure 3: DPoP Header Field ABNF | |||
| 4.2. DPoP Proof JWT Syntax | 4.2. DPoP Proof JWT Syntax | |||
| A DPoP proof is a JWT ([RFC7519]) that is signed (using JSON Web | A DPoP proof is a JWT [RFC7519] that is signed (using JSON Web | |||
| Signature (JWS) [RFC7515]) with a private key chosen by the client | Signature (JWS) [RFC7515]) with a private key chosen by the client | |||
| (see below). The JOSE header of a DPoP JWT MUST contain at least the | (see below). The JOSE Header of a DPoP JWT MUST contain at least the | |||
| following parameters: | following parameters: | |||
| * typ: with value dpop+jwt, which explicitly types the DPoP proof | typ: A field with the value dpop+jwt, which explicitly types the | |||
| JWT as recommended in Section 3.11 of [RFC8725]. | DPoP proof JWT as recommended in Section 3.11 of [RFC8725]. | |||
| * alg: an identifier for a JWS asymmetric digital signature | ||||
| algorithm from [IANA.JOSE.ALGS]. MUST NOT be none or an | alg: An identifier for a JWS asymmetric digital signature algorithm | |||
| identifier for a symmetric algorithm (MAC). | from [IANA.JOSE.ALGS]. It MUST NOT be none or an identifier for a | |||
| * jwk: representing the public key chosen by the client, in JSON Web | symmetric algorithm (Message Authentication Code (MAC)). | |||
| Key (JWK) [RFC7517] format, as defined in Section 4.1.3 of | ||||
| [RFC7515]. MUST NOT contain a private key. | jwk: Represents the public key chosen by the client in JSON Web Key | |||
| (JWK) [RFC7517] format as defined in Section 4.1.3 of [RFC7515]. | ||||
| It MUST NOT contain a private key. | ||||
| The payload of a DPoP proof MUST contain at least the following | The payload of a DPoP proof MUST contain at least the following | |||
| claims: | claims: | |||
| * jti: Unique identifier for the DPoP proof JWT. The value MUST be | jti: Unique identifier for the DPoP proof JWT. The value MUST be | |||
| assigned such that there is a negligible probability that the same | assigned such that there is a negligible probability that the same | |||
| value will be assigned to any other DPoP proof used in the same | value will be assigned to any other DPoP proof used in the same | |||
| context during the time window of validity. Such uniqueness can | context during the time window of validity. Such uniqueness can | |||
| be accomplished by encoding (base64url or any other suitable | be accomplished by encoding (base64url or any other suitable | |||
| encoding) at least 96 bits of pseudorandom data or by using a | encoding) at least 96 bits of pseudorandom data or by using a | |||
| version 4 UUID string according to [RFC4122]. The jti can be used | version 4 Universally Unique Identifier (UUID) string according to | |||
| by the server for replay detection and prevention, see | [RFC4122]. The jti can be used by the server for replay detection | |||
| Section 11.1. | and prevention; see Section 11.1. | |||
| * htm: The value of the HTTP method (Section 9.1 of [RFC9110]) of | ||||
| the request to which the JWT is attached. | htm: The value of the HTTP method (Section 9.1 of [RFC9110]) of the | |||
| * htu: The HTTP target URI (Section 7.1 of [RFC9110]), without query | request to which the JWT is attached. | |||
| and fragment parts, of the request to which the JWT is attached. | ||||
| * iat: Creation timestamp of the JWT ([RFC7519], section 4.1.6]). | htu: The HTTP target URI (Section 7.1 of [RFC9110]) of the request | |||
| to which the JWT is attached, without query and fragment parts. | ||||
| iat: Creation timestamp of the JWT (Section 4.1.6 of [RFC7519]). | ||||
| When the DPoP proof is used in conjunction with the presentation of | When the DPoP proof is used in conjunction with the presentation of | |||
| an access token in protected resource access, see Section 7, the DPoP | an access token in protected resource access (see Section 7), the | |||
| proof MUST also contain the following claim: | DPoP proof MUST also contain the following claim: | |||
| * ath: hash of the access token. The value MUST be the result of a | ath: Hash of the access token. The value MUST be the result of a | |||
| base64url encoding (as defined in Section 2 of [RFC7515]) the | base64url encoding (as defined in Section 2 of [RFC7515]) the | |||
| SHA-256 [SHS] hash of the ASCII encoding of the associated access | SHA-256 [SHS] hash of the ASCII encoding of the associated access | |||
| token's value. | token's value. | |||
| When the authentication server or resource server provides a DPoP- | When the authentication server or resource server provides a DPoP- | |||
| Nonce HTTP header in a response (see Section 8, Section 9), the DPoP | Nonce HTTP header in a response (see Sections 8 and 9), the DPoP | |||
| proof MUST also contain the following claim: | proof MUST also contain the following claim: | |||
| * nonce: A recent nonce provided via the DPoP-Nonce HTTP header. | nonce: A recent nonce provided via the DPoP-Nonce HTTP header. | |||
| A DPoP proof MAY contain other JOSE header parameters or claims as | A DPoP proof MAY contain other JOSE Header Parameters or claims as | |||
| defined by extension, profile, or deployment specific requirements. | defined by extension, profile, or deployment-specific requirements. | |||
| Figure 4 is a conceptual example showing the decoded content of the | Figure 4 is a conceptual example showing the decoded content of the | |||
| DPoP proof in Figure 2. The JSON of the JWT header and payload are | DPoP proof in Figure 2. The JSON of the JWT header and payload are | |||
| shown, but the signature part is omitted. As usual, line breaks and | shown, but the signature part is omitted. As usual, line breaks and | |||
| extra spaces are included for formatting and readability. | extra spaces are included for formatting and readability. | |||
| { | { | |||
| "typ":"dpop+jwt", | "typ":"dpop+jwt", | |||
| "alg":"ES256", | "alg":"ES256", | |||
| "jwk": { | "jwk": { | |||
| skipping to change at page 11, line 23 ¶ | skipping to change at line 469 ¶ | |||
| } | } | |||
| } | } | |||
| . | . | |||
| { | { | |||
| "jti":"-BwC3ESc6acc2lTc", | "jti":"-BwC3ESc6acc2lTc", | |||
| "htm":"POST", | "htm":"POST", | |||
| "htu":"https://server.example.com/token", | "htu":"https://server.example.com/token", | |||
| "iat":1562262616 | "iat":1562262616 | |||
| } | } | |||
| Figure 4: Example JWT content of a DPoP proof | Figure 4: Example JWT Content of a DPoP Proof | |||
| Of the HTTP request, only the HTTP method and URI are included in the | Of the HTTP request, only the HTTP method and URI are included in the | |||
| DPoP JWT, and therefore only these two message parts are covered by | DPoP JWT; therefore, only these two message parts are covered by the | |||
| the DPoP proof. The idea is sign just enough of the HTTP data to | DPoP proof. The idea is to sign just enough of the HTTP data to | |||
| provide reasonable proof-of-possession with respect to the HTTP | provide reasonable proof of possession with respect to the HTTP | |||
| request. This design approach of using only a minimal subset of the | request. This design approach of using only a minimal subset of the | |||
| HTTP header data is to avoid the substantial difficulties inherent in | HTTP header data is to avoid the substantial difficulties inherent in | |||
| attempting to normalize HTTP messages. Nonetheless, DPoP proofs can | attempting to normalize HTTP messages. Nonetheless, DPoP proofs can | |||
| be extended to contain other information of the HTTP request (see | be extended to contain other information of the HTTP request (see | |||
| also Section 11.7). | also Section 11.7). | |||
| 4.3. Checking DPoP Proofs | 4.3. Checking DPoP Proofs | |||
| To validate a DPoP proof, the receiving server MUST ensure that | To validate a DPoP proof, the receiving server MUST ensure the | |||
| following: | ||||
| 1. there is not more than one DPoP HTTP request header field, | 1. There is not more than one DPoP HTTP request header field. | |||
| 2. the DPoP HTTP request header field value is a single well-formed | 2. The DPoP HTTP request header field value is a single and well- | |||
| JWT, | formed JWT. | |||
| 3. all required claims per Section 4.2 are contained in the JWT, | 3. All required claims per Section 4.2 are contained in the JWT. | |||
| 4. the typ JOSE header parameter has the value dpop+jwt, | 4. The typ JOSE Header Parameter has the value dpop+jwt. | |||
| 5. the alg JOSE header parameter indicates a registered asymmetric | 5. The alg JOSE Header Parameter indicates a registered asymmetric | |||
| digital signature algorithm [IANA.JOSE.ALGS], is not none, is | digital signature algorithm [IANA.JOSE.ALGS], is not none, is | |||
| supported by the application, and is acceptable per local | supported by the application, and is acceptable per local | |||
| policy, | policy. | |||
| 6. the JWT signature verifies with the public key contained in the | 6. The JWT signature verifies with the public key contained in the | |||
| jwk JOSE header parameter, | jwk JOSE Header Parameter. | |||
| 7. the jwk JOSE header parameter does not contain a private key, | 7. The jwk JOSE Header Parameter does not contain a private key. | |||
| 8. the htm claim matches the HTTP method of the current request, | 8. The htm claim matches the HTTP method of the current request. | |||
| 9. the htu claim matches the HTTP URI value for the HTTP request in | 9. The htu claim matches the HTTP URI value for the HTTP request in | |||
| which the JWT was received, ignoring any query and fragment | which the JWT was received, ignoring any query and fragment | |||
| parts, | parts. | |||
| 10. if the server provided a nonce value to the client, the nonce | 10. If the server provided a nonce value to the client, the nonce | |||
| claim matches the server-provided nonce value, | claim matches the server-provided nonce value. | |||
| 11. the creation time of the JWT, as determined by either the iat | 11. The creation time of the JWT, as determined by either the iat | |||
| claim or a server managed timestamp via the nonce claim, is | claim or a server managed timestamp via the nonce claim, is | |||
| within an acceptable window (see Section 11.1), | within an acceptable window (see Section 11.1). | |||
| 12. if presented to a protected resource in conjunction with an | 12. If presented to a protected resource in conjunction with an | |||
| access token, | access token, | |||
| * ensure that the value of the ath claim equals the hash of | * ensure that the value of the ath claim equals the hash of | |||
| that access token, | that access token, and | |||
| * confirm that the public key to which the access token is | * confirm that the public key to which the access token is | |||
| bound matches the public key from the DPoP proof. | bound matches the public key from the DPoP proof. | |||
| To reduce the likelihood of false negatives, servers SHOULD employ | To reduce the likelihood of false negatives, servers SHOULD employ | |||
| Syntax-Based Normalization (Section 6.2.2 of [RFC3986]) and Scheme- | syntax-based normalization (Section 6.2.2 of [RFC3986]) and scheme- | |||
| Based Normalization (Section 6.2.3 of [RFC3986]) before comparing the | based normalization (Section 6.2.3 of [RFC3986]) before comparing the | |||
| htu claim. | htu claim. | |||
| These checks may be performed in any order. | These checks may be performed in any order. | |||
| 5. DPoP Access Token Request | 5. DPoP Access Token Request | |||
| To request an access token that is bound to a public key using DPoP, | To request an access token that is bound to a public key using DPoP, | |||
| the client MUST provide a valid DPoP proof JWT in a DPoP header when | the client MUST provide a valid DPoP proof JWT in a DPoP header when | |||
| making an access token request to the authorization server's token | making an access token request to the authorization server's token | |||
| endpoint. This is applicable for all access token requests | endpoint. This is applicable for all access token requests | |||
| regardless of grant type (including, for example, the common | regardless of grant type (e.g., the common authorization_code and | |||
| authorization_code and refresh_token grant types but also extension | refresh_token grant types and extension grants such as the JWT | |||
| grants such as the JWT authorization grant [RFC7523]). The HTTP | authorization grant [RFC7523]). The HTTP request shown in Figure 5 | |||
| request shown in Figure 5 illustrates such an access token request | illustrates such an access token request using an authorization code | |||
| using an authorization code grant with a DPoP proof JWT in the DPoP | grant with a DPoP proof JWT in the DPoP header. Figure 5 uses "\" | |||
| header (with '\' line wrapping per RFC 8792). | line wrapping per [RFC8792]. | |||
| POST /token HTTP/1.1 | POST /token HTTP/1.1 | |||
| Host: server.example.com | Host: server.example.com | |||
| Content-Type: application/x-www-form-urlencoded | Content-Type: application/x-www-form-urlencoded | |||
| DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ | DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ | |||
| VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ | VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ | |||
| nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ | nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ | |||
| QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ | QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ | |||
| oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ | oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ | |||
| WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\ | WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\ | |||
| 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg | 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg | |||
| grant_type=authorization_code\ | grant_type=authorization_code\ | |||
| &client_id=s6BhdRkqt\ | &client_id=s6BhdRkqt\ | |||
| &code=SplxlOBeZQQYbYS6WxSbIA | &code=SplxlOBeZQQYbYS6WxSbIA | |||
| &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb\ | &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb\ | |||
| &code_verifier=bEaL42izcC-o-xBk0K2vuJ6U-y1p9r_wW2dFWIWgjz- | &code_verifier=bEaL42izcC-o-xBk0K2vuJ6U-y1p9r_wW2dFWIWgjz- | |||
| Figure 5: Token Request for a DPoP sender-constrained token using an | Figure 5: Token Request for a DPoP Sender-Constrained Token Using an | |||
| authorization code | Authorization Code | |||
| The DPoP HTTP header field MUST contain a valid DPoP proof JWT. If | The DPoP HTTP header field MUST contain a valid DPoP proof JWT. If | |||
| the DPoP proof is invalid, the authorization server issues an error | the DPoP proof is invalid, the authorization server issues an error | |||
| response per Section 5.2 of [RFC6749] with invalid_dpop_proof as the | response per Section 5.2 of [RFC6749] with invalid_dpop_proof as the | |||
| value of the error parameter. | value of the error parameter. | |||
| To sender-constrain the access token, after checking the validity of | To sender-constrain the access token after checking the validity of | |||
| the DPoP proof, the authorization server associates the issued access | the DPoP proof, the authorization server associates the issued access | |||
| token with the public key from the DPoP proof, which can be | token with the public key from the DPoP proof, which can be | |||
| accomplished as described in Section 6. A token_type of DPoP MUST be | accomplished as described in Section 6. A token_type of DPoP MUST be | |||
| included in the access token response to signal to the client that | included in the access token response to signal to the client that | |||
| the access token was bound to its DPoP key and can be used as | the access token was bound to its DPoP key and can be used as | |||
| described in Section 7.1. The example response shown in Figure 6 | described in Section 7.1. The example response shown in Figure 6 | |||
| illustrates such a response. | illustrates such a response. | |||
| HTTP/1.1 200 OK | HTTP/1.1 200 OK | |||
| Content-Type: application/json | Content-Type: application/json | |||
| skipping to change at page 14, line 5 ¶ | skipping to change at line 581 ¶ | |||
| { | { | |||
| "access_token": "Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU", | "access_token": "Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU", | |||
| "token_type": "DPoP", | "token_type": "DPoP", | |||
| "expires_in": 2677, | "expires_in": 2677, | |||
| "refresh_token": "Q..Zkm29lexi8VnWg2zPW1x-tgGad0Ibc3s3EwM_Ni4-g" | "refresh_token": "Q..Zkm29lexi8VnWg2zPW1x-tgGad0Ibc3s3EwM_Ni4-g" | |||
| } | } | |||
| Figure 6: Access Token Response | Figure 6: Access Token Response | |||
| The example response in Figure 6 includes a refresh token which the | The example response in Figure 6 includes a refresh token that the | |||
| client can use to obtain a new access token when the previous one | client can use to obtain a new access token when the previous one | |||
| expires. Refreshing an access token is a token request using the | expires. Refreshing an access token is a token request using the | |||
| refresh_token grant type made to the authorization server's token | refresh_token grant type made to the authorization server's token | |||
| endpoint. As with all access token requests, the client makes it a | endpoint. As with all access token requests, the client makes it a | |||
| DPoP request by including a DPoP proof, as shown in the Figure 7 | DPoP request by including a DPoP proof, as shown in Figure 7. | |||
| example (with '\' line wrapping per RFC 8792). | Figure 7 uses "\" line wrapping per [RFC8792]. | |||
| POST /token HTTP/1.1 | POST /token HTTP/1.1 | |||
| Host: server.example.com | Host: server.example.com | |||
| Content-Type: application/x-www-form-urlencoded | Content-Type: application/x-www-form-urlencoded | |||
| DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ | DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ | |||
| VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ | VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ | |||
| nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ | nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ | |||
| QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ | QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ | |||
| oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ | oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ | |||
| WF0IjoxNTYyMjY1Mjk2fQ.pAqut2IRDm_De6PR93SYmGBPXpwrAk90e8cP2hjiaG5Qs\ | WF0IjoxNTYyMjY1Mjk2fQ.pAqut2IRDm_De6PR93SYmGBPXpwrAk90e8cP2hjiaG5Qs\ | |||
| GSuKDYW7_X620BxqhvYC8ynrrvZLTk41mSRroapUA | GSuKDYW7_X620BxqhvYC8ynrrvZLTk41mSRroapUA | |||
| grant_type=refresh_token\ | grant_type=refresh_token\ | |||
| &client_id=s6BhdRkqt\ | &client_id=s6BhdRkqt\ | |||
| &refresh_token=Q..Zkm29lexi8VnWg2zPW1x-tgGad0Ibc3s3EwM_Ni4-g | &refresh_token=Q..Zkm29lexi8VnWg2zPW1x-tgGad0Ibc3s3EwM_Ni4-g | |||
| Figure 7: Token Request for a DPoP-bound Token using a Refresh Token | Figure 7: Token Request for a DPoP-Bound Token Using a Refresh Token | |||
| When an authorization server supporting DPoP issues a refresh token | When an authorization server supporting DPoP issues a refresh token | |||
| to a public client that presents a valid DPoP proof at the token | to a public client that presents a valid DPoP proof at the token | |||
| endpoint, the refresh token MUST be bound to the respective public | endpoint, the refresh token MUST be bound to the respective public | |||
| key. The binding MUST be validated when the refresh token is later | key. The binding MUST be validated when the refresh token is later | |||
| presented to get new access tokens. As a result, such a client MUST | presented to get new access tokens. As a result, such a client MUST | |||
| present a DPoP proof for the same key that was used to obtain the | present a DPoP proof for the same key that was used to obtain the | |||
| refresh token each time that refresh token is used to obtain a new | refresh token each time that refresh token is used to obtain a new | |||
| access token. The implementation details of the binding of the | access token. The implementation details of the binding of the | |||
| refresh token are at the discretion of the authorization server. | refresh token are at the discretion of the authorization server. | |||
| Since the authorization server both produces and validates its | Since the authorization server both produces and validates its | |||
| refresh tokens, there is no interoperability consideration in the | refresh tokens, there is no interoperability consideration in the | |||
| specific details of the binding. | specific details of the binding. | |||
| An authorization server MAY elect to issue access tokens which are | An authorization server MAY elect to issue access tokens that are not | |||
| not DPoP bound, which is signaled to the client with a value of | DPoP bound, which is signaled to the client with a value of Bearer in | |||
| Bearer in the token_type parameter of the access token response per | the token_type parameter of the access token response per [RFC6750]. | |||
| [RFC6750]. For a public client that is also issued a refresh token, | For a public client that is also issued a refresh token, this has the | |||
| this has the effect of DPoP-binding the refresh token alone, which | effect of DPoP-binding the refresh token alone, which can improve the | |||
| can improve the security posture even when protected resources are | security posture even when protected resources are not updated to | |||
| not updated to support DPoP. | support DPoP. | |||
| If the access token response contains a different token_type value | If the access token response contains a different token_type value | |||
| than DPoP, the access token protection provided by DPoP is not given. | than DPoP, the access token protection provided by DPoP is not given. | |||
| The client MUST discard the response in this case, if this protection | The client MUST discard the response in this case if this protection | |||
| is deemed important for the security of the application; otherwise, | is deemed important for the security of the application; otherwise, | |||
| it may continue as in a regular OAuth interaction. | the client may continue as in a regular OAuth interaction. | |||
| Refresh tokens issued to confidential clients (those having | Refresh tokens issued to confidential clients (those having | |||
| established authentication credentials with the authorization server) | established authentication credentials with the authorization server) | |||
| are not bound to the DPoP proof public key because they are already | are not bound to the DPoP proof public key because they are already | |||
| sender-constrained with a different existing mechanism. The OAuth | sender-constrained with a different existing mechanism. The OAuth | |||
| 2.0 Authorization Framework [RFC6749] already requires that an | 2.0 Authorization Framework [RFC6749] already requires that an | |||
| authorization server bind refresh tokens to the client to which they | authorization server bind refresh tokens to the client to which they | |||
| were issued and that confidential clients authenticate to the | were issued and that confidential clients authenticate to the | |||
| authorization server when presenting a refresh token. As a result, | authorization server when presenting a refresh token. As a result, | |||
| such refresh tokens are sender-constrained by way of the client | such refresh tokens are sender-constrained by way of the client | |||
| skipping to change at page 15, line 32 ¶ | skipping to change at line 654 ¶ | |||
| allows credential rotation for the client without invalidating | allows credential rotation for the client without invalidating | |||
| refresh tokens) than binding directly to a particular public key. | refresh tokens) than binding directly to a particular public key. | |||
| 5.1. Authorization Server Metadata | 5.1. Authorization Server Metadata | |||
| This document introduces the following authorization server metadata | This document introduces the following authorization server metadata | |||
| [RFC8414] parameter to signal support for DPoP in general and the | [RFC8414] parameter to signal support for DPoP in general and the | |||
| specific JWS alg values the authorization server supports for DPoP | specific JWS alg values the authorization server supports for DPoP | |||
| proof JWTs. | proof JWTs. | |||
| dpop_signing_alg_values_supported A JSON array containing a list of | dpop_signing_alg_values_supported: A JSON array containing a list of | |||
| the JWS alg values (from the [IANA.JOSE.ALGS] registry) supported | the JWS alg values (from the [IANA.JOSE.ALGS] registry) supported | |||
| by the authorization server for DPoP proof JWTs. | by the authorization server for DPoP proof JWTs. | |||
| 5.2. Client Registration Metadata | 5.2. Client Registration Metadata | |||
| The Dynamic Client Registration Protocol [RFC7591] defines an API for | The Dynamic Client Registration Protocol [RFC7591] defines an API for | |||
| dynamically registering OAuth 2.0 client metadata with authorization | dynamically registering OAuth 2.0 client metadata with authorization | |||
| servers. The metadata defined by [RFC7591], and registered | servers. The metadata defined by [RFC7591], and registered | |||
| extensions to it, also imply a general data model for clients that is | extensions to it, also imply a general data model for clients that is | |||
| useful for authorization server implementations even when the Dynamic | useful for authorization server implementations even when the Dynamic | |||
| Client Registration Protocol isn't in play. Such implementations | Client Registration Protocol isn't in play. Such implementations | |||
| will typically have some sort of user interface available for | will typically have some sort of user interface available for | |||
| managing client configuration. | managing client configuration. | |||
| This document introduces the following client registration metadata | This document introduces the following client registration metadata | |||
| [RFC7591] parameter to indicate that the client always uses DPoP when | [RFC7591] parameter to indicate that the client always uses DPoP when | |||
| requesting tokens from the authorization server. | requesting tokens from the authorization server. | |||
| dpop_bound_access_tokens Boolean value specifying whether the client | dpop_bound_access_tokens: A boolean value specifying whether the | |||
| always uses DPoP for token requests. If omitted, the default | client always uses DPoP for token requests. If omitted, the | |||
| value is false. | default value is false. | |||
| If true, the authorization server MUST reject token requests from | If the value is true, the authorization server MUST reject token | |||
| this client that do not contain the DPoP header. | requests from the client that do not contain the DPoP header. | |||
| 6. Public Key Confirmation | 6. Public Key Confirmation | |||
| Resource servers MUST be able to reliably identify whether an access | Resource servers MUST be able to reliably identify whether an access | |||
| token is DPoP-bound and ascertain sufficient information to verify | token is DPoP-bound and ascertain sufficient information to verify | |||
| the binding to the public key of the DPoP proof (see Section 7.1). | the binding to the public key of the DPoP proof (see Section 7.1). | |||
| Such a binding is accomplished by associating the public key with the | Such a binding is accomplished by associating the public key with the | |||
| token in a way that can be accessed by the protected resource, such | token in a way that can be accessed by the protected resource, such | |||
| as embedding the JWK hash in the issued access token directly, using | as embedding the JWK hash in the issued access token directly, using | |||
| the syntax described in Section 6.1, or through token introspection | the syntax described in Section 6.1, or through token introspection | |||
| as described in Section 6.2. Other methods of associating a public | as described in Section 6.2. Other methods of associating a public | |||
| key with an access token are possible, per agreement by the | key with an access token are possible per an agreement by the | |||
| authorization server and the protected resource, but are beyond the | authorization server and the protected resource; however, they are | |||
| scope of this specification. | beyond the scope of this specification. | |||
| Resource servers supporting DPoP MUST ensure that the public key from | Resource servers supporting DPoP MUST ensure that the public key from | |||
| the DPoP proof matches the one bound to the access token. | the DPoP proof matches the one bound to the access token. | |||
| 6.1. JWK Thumbprint Confirmation Method | 6.1. JWK Thumbprint Confirmation Method | |||
| When access tokens are represented as JWTs [RFC7519], the public key | When access tokens are represented as JWTs [RFC7519], the public key | |||
| information is represented using the jkt confirmation method member | information is represented using the jkt confirmation method member | |||
| defined herein. To convey the hash of a public key in a JWT, this | defined herein. To convey the hash of a public key in a JWT, this | |||
| specification introduces the following JWT Confirmation Method | specification introduces the following JWT Confirmation Method | |||
| [RFC7800] member for use under the cnf claim. | [RFC7800] member for use under the cnf claim. | |||
| jkt JWK SHA-256 Thumbprint Confirmation Method. The value of the | jkt: JWK SHA-256 Thumbprint confirmation method. The value of the | |||
| jkt member MUST be the base64url encoding (as defined in | jkt member MUST be the base64url encoding (as defined in | |||
| [RFC7515]) of the JWK SHA-256 Thumbprint (according to [RFC7638]) | [RFC7515]) of the JWK SHA-256 Thumbprint (according to [RFC7638]) | |||
| of the DPoP public key (in JWK format) to which the access token | of the DPoP public key (in JWK format) to which the access token | |||
| is bound. | is bound. | |||
| The following example JWT in Figure 8 with decoded JWT payload shown | The following example JWT in Figure 8 with a decoded JWT payload | |||
| in Figure 9 contains a cnf claim with the jkt JWK Thumbprint | shown in Figure 9 contains a cnf claim with the jkt JWK Thumbprint | |||
| confirmation method member. The jkt value in these examples is the | confirmation method member. The jkt value in these examples is the | |||
| hash of the public key from the DPoP proofs in the examples in | hash of the public key from the DPoP proofs in the examples shown in | |||
| Section 5. (The example uses '\' line wrapping per RFC 8792.) | Section 5. The example uses "\" line wrapping per [RFC8792]. | |||
| eyJhbGciOiJFUzI1NiIsImtpZCI6IkJlQUxrYiJ9.eyJzdWIiOiJzb21lb25lQGV4YW1\ | eyJhbGciOiJFUzI1NiIsImtpZCI6IkJlQUxrYiJ9.eyJzdWIiOiJzb21lb25lQGV4YW1\ | |||
| wbGUuY29tIiwiaXNzIjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20iLCJuYmYiOjE\ | wbGUuY29tIiwiaXNzIjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20iLCJuYmYiOjE\ | |||
| 1NjIyNjI2MTEsImV4cCI6MTU2MjI2NjIxNiwiY25mIjp7ImprdCI6IjBaY09DT1JaTll\ | 1NjIyNjI2MTEsImV4cCI6MTU2MjI2NjIxNiwiY25mIjp7ImprdCI6IjBaY09DT1JaTll\ | |||
| 5LURXcHFxMzBqWnlKR0hUTjBkMkhnbEJWM3VpZ3VBNEkifX0.3Tyo8VTcn6u_PboUmAO\ | 5LURXcHFxMzBqWnlKR0hUTjBkMkhnbEJWM3VpZ3VBNEkifX0.3Tyo8VTcn6u_PboUmAO\ | |||
| YUY1kfAavomW_YwYMkmRNizLJoQzWy2fCo79Zi5yObpIzjWb5xW4OGld7ESZrh0fsrA | YUY1kfAavomW_YwYMkmRNizLJoQzWy2fCo79Zi5yObpIzjWb5xW4OGld7ESZrh0fsrA | |||
| Figure 8: JWT containing a JWK SHA-256 Thumbprint Confirmation | ||||
| Figure 8: JWT Containing a JWK SHA-256 Thumbprint Confirmation | ||||
| { | { | |||
| "sub":"someone@example.com", | "sub":"someone@example.com", | |||
| "iss":"https://server.example.com", | "iss":"https://server.example.com", | |||
| "nbf":1562262611, | "nbf":1562262611, | |||
| "exp":1562266216, | "exp":1562266216, | |||
| "cnf": | "cnf": | |||
| { | { | |||
| "jkt":"0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I" | "jkt":"0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I" | |||
| } | } | |||
| } | } | |||
| Figure 9: JWT Claims Set with a JWK SHA-256 Thumbprint Confirmation | Figure 9: JWT Claims Set with a JWK SHA-256 Thumbprint Confirmation | |||
| 6.2. JWK Thumbprint Confirmation Method in Token Introspection | 6.2. JWK Thumbprint Confirmation Method in Token Introspection | |||
| OAuth 2.0 Token Introspection [RFC7662] defines a method for a | "OAuth 2.0 Token Introspection" [RFC7662] defines a method for a | |||
| protected resource to query an authorization server about the active | protected resource to query an authorization server about the active | |||
| state of an access token as well as to determine metainformation | state of an access token. The protected resource also determines | |||
| about the token. | metainformation about the token. | |||
| For a DPoP-bound access token, the hash of the public key to which | For a DPoP-bound access token, the hash of the public key to which | |||
| the token is bound is conveyed to the protected resource as | the token is bound is conveyed to the protected resource as | |||
| metainformation in a token introspection response. The hash is | metainformation in a token introspection response. The hash is | |||
| conveyed using the same cnf content with jkt member structure as the | conveyed using the same cnf content with jkt member structure as the | |||
| JWK Thumbprint confirmation method, described in Section 6.1, as a | JWK Thumbprint confirmation method, described in Section 6.1, as a | |||
| top-level member of the introspection response JSON. Note that the | top-level member of the introspection response JSON. Note that the | |||
| resource server does not send a DPoP proof with the introspection | resource server does not send a DPoP proof with the introspection | |||
| request and the authorization server does not validate an access | request, and the authorization server does not validate an access | |||
| token's DPoP binding at the introspection endpoint. Rather the | token's DPoP binding at the introspection endpoint. Rather, the | |||
| resource server uses the data of the introspection response to | resource server uses the data of the introspection response to | |||
| validate the access token binding itself locally. | validate the access token binding itself locally. | |||
| If the token_type member is included in the introspection response, | If the token_type member is included in the introspection response, | |||
| it MUST contain the value DPoP. | it MUST contain the value DPoP. | |||
| The example introspection request in Figure 10 and corresponding | The example introspection request in Figure 10 and corresponding | |||
| response in Figure 11 illustrate an introspection exchange for the | response in Figure 11 illustrate an introspection exchange for the | |||
| example DPoP-bound access token that was issued in Figure 6. | example DPoP-bound access token that was issued in Figure 6. | |||
| skipping to change at page 18, line 27 ¶ | skipping to change at line 794 ¶ | |||
| { | { | |||
| "jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I" | "jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I" | |||
| } | } | |||
| } | } | |||
| Figure 11: Example Introspection Response for a DPoP-Bound Access | Figure 11: Example Introspection Response for a DPoP-Bound Access | |||
| Token | Token | |||
| 7. Protected Resource Access | 7. Protected Resource Access | |||
| Requests to DPoP protected resources MUST include both a DPoP proof | Requests to DPoP-protected resources MUST include both a DPoP proof | |||
| as per Section 4 and the access token as described in Section 7.1. | as per Section 4 and the access token as described in Section 7.1. | |||
| The DPoP proof MUST include the ath claim with a valid hash of the | The DPoP proof MUST include the ath claim with a valid hash of the | |||
| associated access token. | associated access token. | |||
| Binding the token value to the proof in this way prevents a proof to | Binding the token value to the proof in this way prevents a proof to | |||
| be used with multiple different access token values across different | be used with multiple different access token values across different | |||
| requests. For example, if a client holds tokens bound to two | requests. For example, if a client holds tokens bound to two | |||
| different resource owners, AT1 and AT2, and uses the same key when | different resource owners, AT1 and AT2, and uses the same key when | |||
| talking to the AS, it's possible that these tokens could be swapped. | talking to the authorization server, it's possible that these tokens | |||
| Without the ath field to bind it, a captured signature applied to AT1 | could be swapped. Without the ath field to bind it, a captured | |||
| could be replayed with AT2 instead, changing the rights and access of | signature applied to AT1 could be replayed with AT2 instead, changing | |||
| the intended request. This same substitution prevention remains for | the rights and access of the intended request. This same | |||
| rotated access tokens within the same combination of client and | substitution prevention remains for rotated access tokens within the | |||
| resource owner -- a rotated token value would require the calculation | same combination of client and resource owner -- a rotated token | |||
| of a new proof. This binding additionally ensures that a proof | value would require the calculation of a new proof. This binding | |||
| intended for use with the access token is not usable without an | additionally ensures that a proof intended for use with the access | |||
| access token, or vice-versa. | token is not usable without an access token, or vice-versa. | |||
| The resource server is required to calculate the hash of the token | The resource server is required to calculate the hash of the token | |||
| value presented and verify that it is the same as the hash value in | value presented and verify that it is the same as the hash value in | |||
| the ath field as described in Section 4.3. Since the ath field value | the ath field as described in Section 4.3. Since the ath field value | |||
| is covered by the DPoP proof's signature, its inclusion binds the | is covered by the DPoP proof's signature, its inclusion binds the | |||
| access token value to the holder of the key used to generate the | access token value to the holder of the key used to generate the | |||
| signature. | signature. | |||
| Note that the ath field alone does not prevent replay of the DPoP | Note that the ath field alone does not prevent replay of the DPoP | |||
| proof or provide binding to the request in which the proof is | proof or provide binding to the request in which the proof is | |||
| presented, and it is still important to check the time window of the | presented, and it is still important to check the time window of the | |||
| proof as well as the included message parameters such as htm and htu. | proof as well as the included message parameters, such as htm and | |||
| htu. | ||||
| 7.1. The DPoP Authentication Scheme | 7.1. The DPoP Authentication Scheme | |||
| A DPoP-bound access token is sent using the Authorization request | A DPoP-bound access token is sent using the Authorization request | |||
| header field per Section 11.6.2 of [RFC9110] using an authentication | header field per Section 11.6.2 of [RFC9110] with an authentication | |||
| scheme of DPoP. The syntax of the Authorization header field for the | scheme of DPoP. The syntax of the Authorization header field for the | |||
| DPoP scheme uses the token68 syntax defined in Section 11.2 of | DPoP scheme uses the token68 syntax defined in Section 11.2 of | |||
| [RFC9110] (repeated below for ease of reference) for credentials. | [RFC9110] for credentials and is repeated below for ease of | |||
| The ABNF notation syntax for DPoP authentication scheme credentials | reference. The ABNF notation syntax for DPoP authentication scheme | |||
| is as follows: | credentials is as follows: | |||
| token68 = 1*( ALPHA / DIGIT / | token68 = 1*( ALPHA / DIGIT / | |||
| "-" / "." / "_" / "~" / "+" / "/" ) *"=" | "-" / "." / "_" / "~" / "+" / "/" ) *"=" | |||
| credentials = "DPoP" 1*SP token68 | credentials = "DPoP" 1*SP token68 | |||
| Figure 12: DPoP Authentication Scheme ABNF | Figure 12: DPoP Authentication Scheme ABNF | |||
| For such an access token, a resource server MUST check that a DPoP | For such an access token, a resource server MUST check that a DPoP | |||
| proof was also received in the DPoP header field of the HTTP request, | proof was also received in the DPoP header field of the HTTP request, | |||
| check the DPoP proof according to the rules in Section 4.3, and check | check the DPoP proof according to the rules in Section 4.3, and check | |||
| that the public key of the DPoP proof matches the public key to which | that the public key of the DPoP proof matches the public key to which | |||
| the access token is bound per Section 6. | the access token is bound per Section 6. | |||
| The resource server MUST NOT grant access to the resource unless all | The resource server MUST NOT grant access to the resource unless all | |||
| checks are successful. | checks are successful. | |||
| Figure 13 shows an example request to a protected resource with a | Figure 13 shows an example request to a protected resource with a | |||
| DPoP-bound access token in the Authorization header and the DPoP | DPoP-bound access token in the Authorization header and the DPoP | |||
| proof in the DPoP header (with '\' line wrapping per RFC 8792). | proof in the DPoP header. The example uses "\" line wrapping per | |||
| Following that is Figure 14, which shows the decoded content of that | [RFC8792]. Figure 14 shows the decoded content of that DPoP proof. | |||
| DPoP proof. The JSON of the JWT header and payload are shown but the | The JSON of the JWT header and payload are shown, but the signature | |||
| signature part is omitted. As usual, line breaks and indentation are | part is omitted. As usual, line breaks and indentation are included | |||
| included for formatting and readability. | for formatting and readability. | |||
| GET /protectedresource HTTP/1.1 | GET /protectedresource HTTP/1.1 | |||
| Host: resource.example.org | Host: resource.example.org | |||
| Authorization: DPoP Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU | Authorization: DPoP Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU | |||
| DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ | DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ | |||
| VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ | VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ | |||
| nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ | nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ | |||
| QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiJlMWozVl9iS2ljOC1MQUVCIiwiaHRtIj\ | QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiJlMWozVl9iS2ljOC1MQUVCIiwiaHRtIj\ | |||
| oiR0VUIiwiaHR1IjoiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLm9yZy9wcm90ZWN0Z\ | oiR0VUIiwiaHR1IjoiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLm9yZy9wcm90ZWN0Z\ | |||
| WRyZXNvdXJjZSIsImlhdCI6MTU2MjI2MjYxOCwiYXRoIjoiZlVIeU8ycjJaM0RaNTNF\ | WRyZXNvdXJjZSIsImlhdCI6MTU2MjI2MjYxOCwiYXRoIjoiZlVIeU8ycjJaM0RaNTNF\ | |||
| c05yV0JiMHhXWG9hTnk1OUlpS0NBcWtzbVFFbyJ9.2oW9RP35yRqzhrtNP86L-Ey71E\ | c05yV0JiMHhXWG9hTnk1OUlpS0NBcWtzbVFFbyJ9.2oW9RP35yRqzhrtNP86L-Ey71E\ | |||
| OptxRimPPToA1plemAgR6pxHF8y6-yqyVnmcw6Fy1dqd-jfxSYoMxhAJpLjA | OptxRimPPToA1plemAgR6pxHF8y6-yqyVnmcw6Fy1dqd-jfxSYoMxhAJpLjA | |||
| Figure 13: DPoP Protected Resource Request | Figure 13: DPoP-Protected Resource Request | |||
| { | { | |||
| "typ":"dpop+jwt", | "typ":"dpop+jwt", | |||
| "alg":"ES256", | "alg":"ES256", | |||
| "jwk": { | "jwk": { | |||
| "kty":"EC", | "kty":"EC", | |||
| "x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs", | "x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs", | |||
| "y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA", | "y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA", | |||
| "crv":"P-256" | "crv":"P-256" | |||
| } | } | |||
| skipping to change at page 20, line 41 ¶ | skipping to change at line 896 ¶ | |||
| "jti":"e1j3V_bKic8-LAEB", | "jti":"e1j3V_bKic8-LAEB", | |||
| "htm":"GET", | "htm":"GET", | |||
| "htu":"https://resource.example.org/protectedresource", | "htu":"https://resource.example.org/protectedresource", | |||
| "iat":1562262618, | "iat":1562262618, | |||
| "ath":"fUHyO2r2Z3DZ53EsNrWBb0xWXoaNy59IiKCAqksmQEo" | "ath":"fUHyO2r2Z3DZ53EsNrWBb0xWXoaNy59IiKCAqksmQEo" | |||
| } | } | |||
| Figure 14: Decoded Content of the DPoP Proof JWT in Figure 13 | Figure 14: Decoded Content of the DPoP Proof JWT in Figure 13 | |||
| Upon receipt of a request to a protected resource within the | Upon receipt of a request to a protected resource within the | |||
| protection space requiring DPoP authentication, if the request does | protection space requiring DPoP authentication, the server can | |||
| not include valid credentials or does not contain an access token | respond with a challenge to the client to provide DPoP authentication | |||
| sufficient for access, the server can respond with a challenge to the | information if the request does not include valid credentials or does | |||
| client to provide DPoP authentication information. Such a challenge | not contain an access token sufficient for access. Such a challenge | |||
| is made using the 401 (Unauthorized) response status code ([RFC9110], | is made using the 401 (Unauthorized) response status code ([RFC9110], | |||
| Section 15.5.2) and the WWW-Authenticate header field ([RFC9110], | Section 15.5.2) and the WWW-Authenticate header field ([RFC9110], | |||
| Section 11.6.1). The server MAY include the WWW-Authenticate header | Section 11.6.1). The server MAY include the WWW-Authenticate header | |||
| in response to other conditions as well. | in response to other conditions as well. | |||
| In such challenges: | In such challenges: | |||
| * The scheme name is DPoP. | * The scheme name is DPoP. | |||
| * The authentication parameter realm MAY be included to indicate the | * The authentication parameter realm MAY be included to indicate the | |||
| scope of protection in the manner described in [RFC9110], | scope of protection in the manner described in [RFC9110], | |||
| Section 11.5. | Section 11.5. | |||
| * A scope authentication parameter MAY be included as defined in | * A scope authentication parameter MAY be included as defined in | |||
| [RFC6750], Section 3. | [RFC6750], Section 3. | |||
| * An error parameter ([RFC6750], Section 3) SHOULD be included to | * An error parameter ([RFC6750], Section 3) SHOULD be included to | |||
| indicate the reason why the request was declined, if the request | indicate the reason why the request was declined, if the request | |||
| included an access token but failed authentication. The error | included an access token but failed authentication. The error | |||
| parameter values described in Section 3.1 of [RFC6750] are | parameter values described in [RFC6750], Section 3.1 are suitable, | |||
| suitable as are any appropriate values defined by extension. The | as are any appropriate values defined by extension. The value | |||
| value use_dpop_nonce can be used as described in Section 9 to | use_dpop_nonce can be used as described in Section 9 to signal | |||
| signal that a nonce is needed in the DPoP proof of subsequent | that a nonce is needed in the DPoP proof of a subsequent | |||
| request(s). And invalid_dpop_proof is used to indicate that the | request(s). Additionally, invalid_dpop_proof is used to indicate | |||
| DPoP proof itself was deemed invalid based on the criteria of | that the DPoP proof itself was deemed invalid based on the | |||
| Section 4.3. | criteria of Section 4.3. | |||
| * An error_description parameter ([RFC6750], Section 3) MAY be | * An error_description parameter ([RFC6750], Section 3) MAY be | |||
| included along with the error parameter to provide developers a | included along with the error parameter to provide developers a | |||
| human-readable explanation that is not meant to be displayed to | human-readable explanation that is not meant to be displayed to | |||
| end-users. | end-users. | |||
| * An algs parameter SHOULD be included to signal to the client the | * An algs parameter SHOULD be included to signal to the client the | |||
| JWS algorithms that are acceptable for the DPoP proof JWT. The | JWS algorithms that are acceptable for the DPoP proof JWT. The | |||
| value of the parameter is a space-delimited list of JWS alg | value of the parameter is a space-delimited list of JWS alg | |||
| (Algorithm) header values ([RFC7515], Section 4.1.1). | (Algorithm) header values ([RFC7515], Section 4.1.1). | |||
| * Additional authentication parameters MAY be used and unknown | * Additional authentication parameters MAY be used, and unknown | |||
| parameters MUST be ignored by recipients. | parameters MUST be ignored by recipients. | |||
| For example, in response to a protected resource request without | Figure 15 shows a response to a protected resource request without | |||
| authentication: | authentication. | |||
| HTTP/1.1 401 Unauthorized | HTTP/1.1 401 Unauthorized | |||
| WWW-Authenticate: DPoP algs="ES256 PS256" | WWW-Authenticate: DPoP algs="ES256 PS256" | |||
| Figure 15: HTTP 401 Response to a Protected Resource Request without | Figure 15: HTTP 401 Response to a Protected Resource Request without | |||
| Authentication | Authentication | |||
| And in response to a protected resource request that was rejected | Figure 16 shows a response to a protected resource request that was | |||
| because the confirmation of the DPoP binding in the access token | rejected due to the failed confirmation of the DPoP binding in the | |||
| failed (with '\' line wrapping per RFC 8792): | access token. Figure 16 uses "\" line wrapping per [RFC8792]. | |||
| HTTP/1.1 401 Unauthorized | HTTP/1.1 401 Unauthorized | |||
| WWW-Authenticate: DPoP error="invalid_token", \ | WWW-Authenticate: DPoP error="invalid_token", \ | |||
| error_description="Invalid DPoP key binding", algs="ES256" | error_description="Invalid DPoP key binding", algs="ES256" | |||
| Figure 16: HTTP 401 Response to a Protected Resource Request with | Figure 16: HTTP 401 Response to a Protected Resource Request with | |||
| an Invalid Token | an Invalid Token | |||
| Note that browser-based client applications using CORS [WHATWG.Fetch] | Note that browser-based client applications using Cross-Origin | |||
| only have access to CORS-safelisted response HTTP headers by default. | Resource Sharing (CORS) [WHATWG.Fetch] only have access to CORS- | |||
| In order for the application to obtain and use the WWW-Authenticate | safelisted response HTTP headers by default. In order for the | |||
| HTTP response header value, the server needs to make it available to | application to obtain and use the WWW-Authenticate HTTP response | |||
| the application by including WWW-Authenticate in the Access-Control- | header value, the server needs to make it available to the | |||
| application by including WWW-Authenticate in the Access-Control- | ||||
| Expose-Headers response header list value. | Expose-Headers response header list value. | |||
| This authentication scheme is for origin-server authentication only. | This authentication scheme is for origin-server authentication only. | |||
| Therefore, this authentication scheme MUST NOT be used with the | Therefore, this authentication scheme MUST NOT be used with the | |||
| Proxy-Authenticate or Proxy-Authorization header fields. | Proxy-Authenticate or Proxy-Authorization header fields. | |||
| Note that the syntax of the Authorization header field for this | Note that the syntax of the Authorization header field for this | |||
| authentication scheme follows the usage of the Bearer scheme defined | authentication scheme follows the usage of the Bearer scheme defined | |||
| in Section 2.1 of [RFC6750]. While not the preferred credential | in Section 2.1 of [RFC6750]. While it is not the preferred | |||
| syntax of [RFC9110], it is compatible with the general authentication | credential syntax of [RFC9110], it is compatible with the general | |||
| framework therein and was used for consistency and familiarity with | authentication framework therein and is used for consistency and | |||
| the Bearer scheme. | familiarity with the Bearer scheme. | |||
| 7.2. Compatibility with the Bearer Authentication Scheme | 7.2. Compatibility with the Bearer Authentication Scheme | |||
| Protected resources simultaneously supporting both the DPoP and | Protected resources simultaneously supporting both the DPoP and | |||
| Bearer schemes need to update how evaluation of bearer tokens is | Bearer schemes need to update how the evaluation process is performed | |||
| performed to prevent downgraded usage of a DPoP-bound access token. | for bearer tokens to prevent downgraded usage of a DPoP-bound access | |||
| Specifically, such a protected resource MUST reject a DPoP-bound | token. Specifically, such a protected resource MUST reject a DPoP- | |||
| access token received as a bearer token per [RFC6750]. | bound access token received as a bearer token per [RFC6750]. | |||
| Section 11.6.1 of [RFC9110] allows a protected resource to indicate | Section 11.6.1 of [RFC9110] allows a protected resource to indicate | |||
| support for multiple authentication schemes (i.e., Bearer and DPoP) | support for multiple authentication schemes (i.e., Bearer and DPoP) | |||
| with the WWW-Authenticate header field of a 401 (Unauthorized) | with the WWW-Authenticate header field of a 401 (Unauthorized) | |||
| response. | response. | |||
| A protected resource that supports only [RFC6750] and is unaware of | A protected resource that supports only [RFC6750] and is unaware of | |||
| DPoP would most presumably accept a DPoP-bound access token as a | DPoP would most presumably accept a DPoP-bound access token as a | |||
| bearer token (JWT [RFC7519] says to ignore unrecognized claims, | bearer token (JWT [RFC7519] says to ignore unrecognized claims, | |||
| Introspection [RFC7662] says that other parameters might be present | Introspection [RFC7662] says that other parameters might be present | |||
| while placing no functional requirements on their presence, and | while placing no functional requirements on their presence, and | |||
| [RFC6750] is effectively silent on the content of the access token as | [RFC6750] is effectively silent on the content of the access token | |||
| it relates to validity). As such, a client can send a DPoP-bound | since it relates to validity). As such, a client can send a DPoP- | |||
| access token using the Bearer scheme upon receipt of a WWW- | bound access token using the Bearer scheme upon receipt of a WWW- | |||
| Authenticate: Bearer challenge from a protected resource (or if it | Authenticate: Bearer challenge from a protected resource (or it can | |||
| has prior such knowledge about the capabilities of the protected | send a DPoP-bound access token if it has prior knowledge of the | |||
| resource). The effect of this likely simplifies the logistics of | capabilities of the protected resource). The effect of this likely | |||
| phased upgrades to protected resources in their support DPoP or even | simplifies the logistics of phased upgrades to protected resources in | |||
| prolonged deployments of protected resources with mixed token type | their support DPoP or prolonged deployments of protected resources | |||
| support. | with mixed token type support. | |||
| If a protected resource supporting both Bearer and DPoP schemes | If a protected resource supporting both Bearer and DPoP schemes | |||
| elects to respond with multiple WWW-Authenticate challenges, | elects to respond with multiple WWW-Authenticate challenges, | |||
| attention should be paid to which challenge(s) should deliver the | attention should be paid to which challenge(s) should deliver the | |||
| actual error information. It is RECOMMENDED that the following rules | actual error information. It is RECOMMENDED that the following rules | |||
| be adhered to: | be adhered to: | |||
| * If no authentication information has been included with the | * If no authentication information has been included with the | |||
| request, then the challenges SHOULD NOT include an error code or | request, then the challenges SHOULD NOT include an error code or | |||
| other error information, as per [RFC6750], Section 3.1 | other error information, as per Section 3.1 of [RFC6750] | |||
| (Figure 17). | (Figure 17). | |||
| * If the mechanism used to attempt authentication could be | * If the mechanism used to attempt authentication could be | |||
| established unambiguously, then the corresponding challenge SHOULD | established unambiguously, then the corresponding challenge SHOULD | |||
| be used to deliver error information (Figure 18). | be used to deliver error information (Figure 18). | |||
| * Otherwise, both Bearer and DPoP challenged MAY be used to deliver | * Otherwise, both Bearer and DPoP challenges MAY be used to deliver | |||
| error information (Figure 19). | error information (Figure 19). | |||
| (Where needed, the following examples use '\' line wrapping per RFC | The following examples use "\" line wrapping per [RFC8792]. | |||
| 8792.) | ||||
| GET /protectedresource HTTP/1.1 | GET /protectedresource HTTP/1.1 | |||
| Host: resource.example.org | Host: resource.example.org | |||
| HTTP/1.1 401 Unauthorized | HTTP/1.1 401 Unauthorized | |||
| WWW-Authenticate: Bearer, DPoP algs="ES256 PS256" | WWW-Authenticate: Bearer, DPoP algs="ES256 PS256" | |||
| Figure 17: HTTP 401 Response to a Protected Resource Request without | Figure 17: HTTP 401 Response to a Protected Resource Request without | |||
| Authentication | Authentication | |||
| skipping to change at page 24, line 22 ¶ | skipping to change at line 1058 ¶ | |||
| error_description="Multiple methods used to include access token", \ | error_description="Multiple methods used to include access token", \ | |||
| DPoP algs="ES256 PS256", error="invalid_request", \ | DPoP algs="ES256 PS256", error="invalid_request", \ | |||
| error_description="Multiple methods used to include access token" | error_description="Multiple methods used to include access token" | |||
| Figure 19: HTTP 400 Response to a Protected Resource Request with | Figure 19: HTTP 400 Response to a Protected Resource Request with | |||
| Ambiguous Authentication | Ambiguous Authentication | |||
| 7.3. Client Considerations | 7.3. Client Considerations | |||
| Authorization including a DPoP proof may not be idempotent (depending | Authorization including a DPoP proof may not be idempotent (depending | |||
| on server enforcement of jti, iat and nonce claims). Consequently, | on server enforcement of jti, iat, and nonce claims). Consequently, | |||
| all previously idempotent requests for protected resources that were | all previously idempotent requests for protected resources that were | |||
| previously idempotent may no longer be idempotent. It is RECOMMENDED | previously idempotent may no longer be idempotent. It is RECOMMENDED | |||
| that clients generate a unique DPoP proof even when retrying | that clients generate a unique DPoP proof, even when retrying | |||
| idempotent requests in response to HTTP errors generally understood | idempotent requests in response to HTTP errors generally understood | |||
| as transient. | as transient. | |||
| Clients that encounter frequent network errors may experience | Clients that encounter frequent network errors may experience | |||
| additional challenges when interacting with servers with more strict | additional challenges when interacting with servers with stricter | |||
| nonce validation implementations. | nonce validation implementations. | |||
| 8. Authorization Server-Provided Nonce | 8. Authorization Server-Provided Nonce | |||
| This section specifies a mechanism using opaque nonces provided by | This section specifies a mechanism using opaque nonces provided by | |||
| the server that can be used to limit the lifetime of DPoP proofs. | the server that can be used to limit the lifetime of DPoP proofs. | |||
| Without employing such a mechanism, a malicious party controlling the | Without employing such a mechanism, a malicious party controlling the | |||
| client (including potentially the end-user) can create DPoP proofs | client (potentially including the end-user) can create DPoP proofs | |||
| for use arbitrarily far in the future. | for use arbitrarily far in the future. | |||
| Including a nonce value contributed by the authorization server in | Including a nonce value contributed by the authorization server in | |||
| the DPoP proof MAY be used by authorization servers to limit the | the DPoP proof MAY be used by authorization servers to limit the | |||
| lifetime of DPoP proofs. The server determines when and if to issue | lifetime of DPoP proofs. The server determines when to issue a new | |||
| a new DPoP nonce challenge thereby requiring the use of the nonce | DPoP nonce challenge and if it is needed, thereby requiring the use | |||
| value in subsequent DPoP proofs. The logic through which the server | of the nonce value in subsequent DPoP proofs. The logic through | |||
| makes that determination is out of scope of this document. | which the server makes that determination is out of scope of this | |||
| document. | ||||
| An authorization server MAY supply a nonce value to be included by | An authorization server MAY supply a nonce value to be included by | |||
| the client in DPoP proofs sent. In this case, the authorization | the client in DPoP proofs sent. In this case, the authorization | |||
| server responds to requests not including a nonce with an HTTP 400 | server responds to requests that do not include a nonce with an HTTP | |||
| (Bad Request) error response per Section 5.2 of [RFC6749] using | 400 (Bad Request) error response per Section 5.2 of [RFC6749] using | |||
| use_dpop_nonce as the error code value. The authorization server | use_dpop_nonce as the error code value. The authorization server | |||
| includes a DPoP-Nonce HTTP header in the response supplying a nonce | includes a DPoP-Nonce HTTP header in the response supplying a nonce | |||
| value to be used when sending the subsequent request. Nonce values | value to be used when sending the subsequent request. Nonce values | |||
| MUST be unpredictable. This same error code is used when supplying a | MUST be unpredictable. This same error code is used when supplying a | |||
| new nonce value when there was a nonce mismatch. The client will | new nonce value when there was a nonce mismatch. The client will | |||
| typically retry the request with the new nonce value supplied upon | typically retry the request with the new nonce value supplied upon | |||
| receiving a use_dpop_nonce error with an accompanying nonce value. | receiving a use_dpop_nonce error with an accompanying nonce value. | |||
| For example, in response to a token request without a nonce when the | For example, in response to a token request without a nonce when the | |||
| authorization server requires one, the authorization server can | authorization server requires one, the authorization server can | |||
| skipping to change at page 25, line 32 ¶ | skipping to change at line 1118 ¶ | |||
| "Authorization server requires nonce in DPoP proof" | "Authorization server requires nonce in DPoP proof" | |||
| } | } | |||
| Figure 20: HTTP 400 Response to a Token Request without a Nonce | Figure 20: HTTP 400 Response to a Token Request without a Nonce | |||
| Other HTTP headers and JSON fields MAY also be included in the error | Other HTTP headers and JSON fields MAY also be included in the error | |||
| response, but there MUST NOT be more than one DPoP-Nonce header. | response, but there MUST NOT be more than one DPoP-Nonce header. | |||
| Upon receiving the nonce, the client is expected to retry its token | Upon receiving the nonce, the client is expected to retry its token | |||
| request using a DPoP proof including the supplied nonce value in the | request using a DPoP proof including the supplied nonce value in the | |||
| nonce claim of the DPoP proof. An example unencoded JWT Payload of | nonce claim of the DPoP proof. An example unencoded JWT payload of | |||
| such a DPoP proof including a nonce is: | such a DPoP proof including a nonce is shown below. | |||
| { | { | |||
| "jti": "-BwC3ESc6acc2lTc", | "jti": "-BwC3ESc6acc2lTc", | |||
| "htm": "POST", | "htm": "POST", | |||
| "htu": "https://server.example.com/token", | "htu": "https://server.example.com/token", | |||
| "iat": 1562262616, | "iat": 1562262616, | |||
| "nonce": "eyJ7S_zG.eyJH0-Z.HX4w-7v" | "nonce": "eyJ7S_zG.eyJH0-Z.HX4w-7v" | |||
| } | } | |||
| Figure 21: DPoP Proof Payload Including a Nonce Value | Figure 21: DPoP Proof Payload including a Nonce Value | |||
| The nonce is opaque to the client. | The nonce is opaque to the client. | |||
| If the nonce claim in the DPoP proof does not exactly match a nonce | If the nonce claim in the DPoP proof does not exactly match a nonce | |||
| recently supplied by the authorization server to the client, the | recently supplied by the authorization server to the client, the | |||
| authorization server MUST reject the request. The rejection response | authorization server MUST reject the request. The rejection response | |||
| MAY include a DPoP-Nonce HTTP header providing a new nonce value to | MAY include a DPoP-Nonce HTTP header providing a new nonce value to | |||
| use for subsequent requests. | use for subsequent requests. | |||
| The intent is that clients need to keep only one nonce value and | The intent is that clients need to keep only one nonce value and | |||
| servers keep a window of recent nonces. That said, transient | servers need to keep a window of recent nonces. That said, transient | |||
| circumstances may arise in which the server's and client's stored | circumstances may arise in which the stored nonce values for the | |||
| nonce values differ. However, this situation is self-correcting; | server and the client differ. However, this situation is self- | |||
| with any rejection message, the server can send the client the nonce | correcting. With any rejection message, the server can send the | |||
| value that the server wants it to use and the client can store that | client the nonce value it wants to use to the client, and the client | |||
| nonce value and retry the request with it. Even if the client and/or | can store that nonce value and retry the request with it. Even if | |||
| server discard their stored nonce values, that situation is also | the client and/or server discard their stored nonce values, that | |||
| self-correcting because new nonce values can be communicated when | situation is also self-correcting because new nonce values can be | |||
| responding to or retrying failed requests. | communicated when responding to or retrying failed requests. | |||
| Note that browser-based client applications using CORS [WHATWG.Fetch] | Note that browser-based client applications using CORS [WHATWG.Fetch] | |||
| only have access to CORS-safelisted response HTTP headers by default. | only have access to CORS-safelisted response HTTP headers by default. | |||
| In order for the application to obtain and use the DPoP-Nonce HTTP | In order for the application to obtain and use the DPoP-Nonce HTTP | |||
| response header value, the server needs to make it available to the | response header value, the server needs to make it available to the | |||
| application by including DPoP-Nonce in the Access-Control-Expose- | application by including DPoP-Nonce in the Access-Control-Expose- | |||
| Headers response header list value. | Headers response header list value. | |||
| 8.1. Nonce Syntax | 8.1. Nonce Syntax | |||
| The nonce syntax in ABNF as used by [RFC6749] (which is the same as | The nonce syntax in ABNF as used by [RFC6749] (which is the same as | |||
| the scope-token syntax) is: | the scope-token syntax) is shown below. | |||
| nonce = 1*NQCHAR | nonce = 1*NQCHAR | |||
| Figure 22: Nonce ABNF | Figure 22: Nonce ABNF | |||
| 8.2. Providing a New Nonce Value | 8.2. Providing a New Nonce Value | |||
| It is up to the authorization server when to supply a new nonce value | It is up to the authorization server when to supply a new nonce value | |||
| for the client to use. The client is expected to use the existing | for the client to use. The client is expected to use the existing | |||
| supplied nonce in DPoP proofs until the server supplies a new nonce | supplied nonce in DPoP proofs until the server supplies a new nonce | |||
| value. | value. | |||
| The authorization server MAY supply the new nonce in the same way | The authorization server MAY supply the new nonce in the same way | |||
| that the initial one was supplied: by using a DPoP-Nonce HTTP header | that the initial one was supplied: by using a DPoP-Nonce HTTP header | |||
| in the response. The DPoP-Nonce HTTP header field uses the nonce | in the response. The DPoP-Nonce HTTP header field uses the nonce | |||
| syntax defined in Section 8.1. Of course, each time this happens it | syntax defined in Section 8.1. Each time this happens, it requires | |||
| requires an extra protocol round trip. | an extra protocol round trip. | |||
| A more efficient manner of supplying a new nonce value is also | A more efficient manner of supplying a new nonce value is also | |||
| defined -- by including a DPoP-Nonce HTTP header in the HTTP 200 (OK) | defined by including a DPoP-Nonce HTTP header in the HTTP 200 (OK) | |||
| response from the previous request. The client MUST use the new | response from the previous request. The client MUST use the new | |||
| nonce value supplied for the next token request, and for all | nonce value supplied for the next token request and for all | |||
| subsequent token requests until the authorization server supplies a | subsequent token requests until the authorization server supplies a | |||
| new nonce. | new nonce. | |||
| Responses that include the DPoP-Nonce HTTP header should be | Responses that include the DPoP-Nonce HTTP header should be | |||
| uncacheable (e.g., using Cache-Control: no-store in response to a GET | uncacheable (e.g., using Cache-Control: no-store in response to a GET | |||
| request) to prevent the response being used to serve a subsequent | request) to prevent the response from being used to serve a | |||
| request and a stale nonce value being used as a result. | subsequent request and a stale nonce value from being used as a | |||
| result. | ||||
| An example 200 OK response providing a new nonce value is: | An example 200 OK response providing a new nonce value is shown | |||
| below. | ||||
| HTTP/1.1 200 OK | HTTP/1.1 200 OK | |||
| Cache-Control: no-store | Cache-Control: no-store | |||
| DPoP-Nonce: eyJ7S_zG.eyJbYu3.xQmBj-1 | DPoP-Nonce: eyJ7S_zG.eyJbYu3.xQmBj-1 | |||
| Figure 23: HTTP 200 Response Providing the Next Nonce Value | Figure 23: HTTP 200 Response Providing the Next Nonce Value | |||
| 9. Resource Server-Provided Nonce | 9. Resource Server-Provided Nonce | |||
| Resource servers can also choose to provide a nonce value to be | Resource servers can also choose to provide a nonce value to be | |||
| included in DPoP proofs sent to them. They provide the nonce using | included in DPoP proofs sent to them. They provide the nonce using | |||
| the DPoP-Nonce header in the same way that authorization servers do | the DPoP-Nonce header in the same way that authorization servers do | |||
| as described in Section 8 and Section 8.2. The error signaling is | as described in Sections 8 and 8.2. The error signaling is performed | |||
| performed as described in Section 7.1. Resource servers use an HTTP | as described in Section 7.1. Resource servers use an HTTP 401 | |||
| 401 (Unauthorized) error code with an accompanying WWW-Authenticate: | (Unauthorized) error code with an accompanying WWW-Authenticate: DPoP | |||
| DPoP value and DPoP-Nonce value to accomplish this. | value and DPoP-Nonce value to accomplish this. | |||
| For example, in response to a resource request without a nonce when | For example, in response to a resource request without a nonce when | |||
| the resource server requires one, the resource server can respond | the resource server requires one, the resource server can respond | |||
| with a DPoP-Nonce value such as the following to provide a nonce | with a DPoP-Nonce value such as the following to provide a nonce | |||
| value to include in the DPoP proof (with '\' line wrapping per RFC | value to include in the DPoP proof. The example below uses "\" line | |||
| 8792): | wrapping per [RFC8792]. | |||
| HTTP/1.1 401 Unauthorized | HTTP/1.1 401 Unauthorized | |||
| WWW-Authenticate: DPoP error="use_dpop_nonce", \ | WWW-Authenticate: DPoP error="use_dpop_nonce", \ | |||
| error_description="Resource server requires nonce in DPoP proof" | error_description="Resource server requires nonce in DPoP proof" | |||
| DPoP-Nonce: eyJ7S_zG.eyJH0-Z.HX4w-7v | DPoP-Nonce: eyJ7S_zG.eyJH0-Z.HX4w-7v | |||
| Figure 24: HTTP 401 Response to a Resource Request without a Nonce | Figure 24: HTTP 401 Response to a Resource Request without a Nonce | |||
| Note that the nonces provided by an authorization server and a | Note that the nonces provided by an authorization server and a | |||
| resource server are different and should not be confused with one | resource server are different and should not be confused with one | |||
| another, since nonces will be only accepted by the server that issued | another since nonces will be only accepted by the server that issued | |||
| them. Likewise, should a client use multiple authorization servers | them. Likewise, should a client use multiple authorization servers | |||
| and/or resource servers, a nonce issued by any of them should be used | and/or resource servers, a nonce issued by any of them should be used | |||
| only at the issuing server. Developers should also take care to not | only at the issuing server. Developers should also be careful to not | |||
| confuse DPoP nonces with the OpenID Connect [OpenID.Core] ID Token | confuse DPoP nonces with the OpenID Connect [OpenID.Core] ID Token | |||
| nonce. | nonce. | |||
| 10. Authorization Code Binding to DPoP Key | 10. Authorization Code Binding to a DPoP Key | |||
| Binding the authorization code issued to the client's proof-of- | Binding the authorization code issued to the client's proof-of- | |||
| possession key can enable end-to-end binding of the entire | possession key can enable end-to-end binding of the entire | |||
| authorization flow. This specification defines the dpop_jkt | authorization flow. This specification defines the dpop_jkt | |||
| authorization request parameter for this purpose. The value of the | authorization request parameter for this purpose. The value of the | |||
| dpop_jkt authorization request parameter is the JSON Web Key (JWK) | dpop_jkt authorization request parameter is the JWK Thumbprint | |||
| Thumbprint [RFC7638] of the proof-of-possession public key using the | [RFC7638] of the proof-of-possession public key using the SHA-256 | |||
| SHA-256 hash function - the same value as used for the jkt | hash function, which is the same value as used for the jkt | |||
| confirmation method defined in Section 6.1. | confirmation method defined in Section 6.1. | |||
| When a token request is received, the authorization server computes | When a token request is received, the authorization server computes | |||
| the JWK thumbprint of the proof-of-possession public key in the DPoP | the JWK Thumbprint of the proof-of-possession public key in the DPoP | |||
| proof and verifies that it matches the dpop_jkt parameter value in | proof and verifies that it matches the dpop_jkt parameter value in | |||
| the authorization request. If they do not match, it MUST reject the | the authorization request. If they do not match, it MUST reject the | |||
| request. | request. | |||
| An example authorization request using the dpop_jkt authorization | An example authorization request using the dpop_jkt authorization | |||
| request parameter follows (with '\' line wrapping per RFC 8792): | request parameter is shown below and uses "\" line wrapping per | |||
| [RFC8792]. | ||||
| GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz\ | GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz\ | |||
| &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb\ | &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb\ | |||
| &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM\ | &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM\ | |||
| &code_challenge_method=S256\ | &code_challenge_method=S256\ | |||
| &dpop_jkt=NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs HTTP/1.1 | &dpop_jkt=NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs HTTP/1.1 | |||
| Host: server.example.com | Host: server.example.com | |||
| Figure 25: Authorization Request using the dpop_jkt Parameter | Figure 25: Authorization Request Using the dpop_jkt Parameter | |||
| Use of the dpop_jkt authorization request parameter is OPTIONAL. | Use of the dpop_jkt authorization request parameter is OPTIONAL. | |||
| Note that the dpop_jkt authorization request parameter MAY also be | Note that the dpop_jkt authorization request parameter MAY also be | |||
| used in combination with PKCE [RFC7636], which is recommended by | used in combination with Proof Key for Code Exchange (PKCE) | |||
| [I-D.ietf-oauth-security-topics] as a countermeasure to authorization | [RFC7636], which is recommended by [SECURITY-TOPICS] as a | |||
| code injection. The dpop_jkt authorization request parameter only | countermeasure to authorization code injection. The dpop_jkt | |||
| provides similar protections when a unique DPoP key is used for each | authorization request parameter only provides similar protections | |||
| authorization request. | when a unique DPoP key is used for each authorization request. | |||
| 10.1. DPoP with Pushed Authorization Requests | 10.1. DPoP with Pushed Authorization Requests | |||
| When Pushed Authorization Requests (PAR, [RFC9126]) are used in | When Pushed Authorization Requests (PARs) [RFC9126] are used in | |||
| conjunction with DPoP, there are two ways in which the DPoP key can | conjunction with DPoP, there are two ways in which the DPoP key can | |||
| be communicated in the PAR request: | be communicated in the PAR request: | |||
| * The dpop_jkt parameter can be used as described in Section 10 to | * The dpop_jkt parameter can be used as described in Section 10 to | |||
| bind the issued authorization code to a specific key. In this | bind the issued authorization code to a specific key. In this | |||
| case, dpop_jkt MUST be included alongside other authorization | case, dpop_jkt MUST be included alongside other authorization | |||
| request parameters in the POST body of the PAR request. | request parameters in the POST body of the PAR request. | |||
| * Alternatively, the DPoP header can be added to the PAR request. | * Alternatively, the DPoP header can be added to the PAR request. | |||
| In this case, the authorization server MUST check the provided | In this case, the authorization server MUST check the provided | |||
| DPoP proof JWT as defined in Section 4.3. It MUST further behave | DPoP proof JWT as defined in Section 4.3. It MUST further behave | |||
| as if the contained public key's thumbprint was provided using | as if the contained public key's thumbprint was provided using | |||
| dpop_jkt, i.e., reject the subsequent token request unless a DPoP | dpop_jkt, i.e., reject the subsequent token request unless a DPoP | |||
| proof for the same key is provided. This can help to simplify the | proof for the same key is provided. This can help to simplify the | |||
| implementation of the client, as it can "blindly" attach the DPoP | implementation of the client, as it can "blindly" attach the DPoP | |||
| header to all requests to the authorization server regardless of | header to all requests to the authorization server regardless of | |||
| the type of request. Additionally, it provides a stronger | the type of request. Additionally, it provides a stronger | |||
| binding, as the DPoP header contains a proof of possession of the | binding, as the DPoP header contains a proof of possession of the | |||
| private key. | private key. | |||
| Both mechanisms MUST be supported by an authorization server that | Both mechanisms MUST be supported by an authorization server that | |||
| supports PAR and DPoP. If both mechanisms are used at the same time, | supports PAR and DPoP. If both mechanisms are used at the same time, | |||
| the authorization server MUST reject the request if the JWK | the authorization server MUST reject the request if the JWK | |||
| Thumbprint in dpop_jkt does not match the public key in the DPoP | Thumbprint in dpop_jkt does not match the public key in the DPoP | |||
| header. | header. | |||
| Allowing both mechanisms ensures that clients that use dpop_jkt do | Allowing both mechanisms ensures that clients using dpop_jkt do not | |||
| not need to distinguish between front-channel and pushed | need to distinguish between front-channel and pushed authorization | |||
| authorization requests, and at the same time, clients that only have | requests, and at the same time, clients that only have one code path | |||
| one code path for protecting all calls to authorization server | for protecting all calls to authorization server endpoints do not | |||
| endpoints do not need to distinguish between requests to the PAR | need to distinguish between requests to the PAR endpoint and the | |||
| endpoint and the token endpoint. | token endpoint. | |||
| 11. Security Considerations | 11. Security Considerations | |||
| In DPoP, the prevention of token replay at a different endpoint (see | In DPoP, the prevention of token replay at a different endpoint (see | |||
| Section 2) is achieved through authentication of the server per | Section 2) is achieved through authentication of the server per | |||
| [RFC6125] and binding of the DPoP proof to a certain URI and HTTP | [RFC6125] and the binding of the DPoP proof to a certain URI and HTTP | |||
| method. DPoP, however, has a somewhat different nature of protection | method. However, DPoP has a somewhat different nature of protection | |||
| than TLS-based methods such as OAuth Mutual TLS [RFC8705] or OAuth | than TLS-based methods such as OAuth Mutual TLS [RFC8705] or OAuth | |||
| Token Binding [I-D.ietf-oauth-token-binding] (see also Section 11.1 | Token Binding [TOKEN-BINDING] (see also Sections 11.1 and 11.7). | |||
| and Section 11.7). TLS-based mechanisms can leverage a tight | TLS-based mechanisms can leverage a tight integration between the TLS | |||
| integration between the TLS layer and the application layer to | layer and the application layer to achieve strong message integrity, | |||
| achieve strong message integrity, authenticity, and replay | authenticity, and replay protection. | |||
| protection. | ||||
| 11.1. DPoP Proof Replay | 11.1. DPoP Proof Replay | |||
| If an adversary is able to get hold of a DPoP proof JWT, the | 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 | adversary could replay that token at the same endpoint (the HTTP | |||
| endpoint and method are enforced via the respective claims in the | endpoint and method are enforced via the respective claims in the | |||
| JWTs). To limit this, servers MUST only accept DPoP proofs for a | JWTs). To limit this, servers MUST only accept DPoP proofs for a | |||
| limited time after their creation (preferably only for a relatively | limited time after their creation (preferably only for a relatively | |||
| brief period on the order of seconds or minutes). | brief period on the order of seconds or minutes). | |||
| To prevent multiple uses of the same DPoP proof, servers can store, | In the context of the target URI, servers can store the jti value of | |||
| in the context of the target URI, the jti value of each DPoP proof | each DPoP proof for the time window in which the respective DPoP | |||
| for the time window in which the respective DPoP proof JWT would be | proof JWT would be accepted to prevent multiple uses of the same DPoP | |||
| accepted. HTTP requests to the same URI for which the jti value has | proof. HTTP requests to the same URI for which the jti value has | |||
| been seen before would be declined. Such a single-use check, when | been seen before would be declined. When strictly enforced, such a | |||
| strictly enforced, provides a very strong protection against DPoP | single-use check provides a very strong protection against DPoP proof | |||
| proof replay, but may not always be feasible in practice, e.g., when | replay, but it may not always be feasible in practice, e.g., when | |||
| multiple servers behind a single endpoint have no shared state. | multiple servers behind a single endpoint have no shared state. | |||
| In order to guard against memory exhaustion attacks, a server that is | In order to guard against memory exhaustion attacks, a server that is | |||
| tracking jti values should reject DPoP proof JWTs with unnecessarily | tracking jti values should reject DPoP proof JWTs with unnecessarily | |||
| large jti values or store only a hash thereof. | large jti values or store only a hash thereof. | |||
| Note: To accommodate for clock offsets, the server MAY accept DPoP | Note: To accommodate for clock offsets, the server MAY accept DPoP | |||
| proofs that carry an iat time in the reasonably near future (on the | proofs that carry an iat time in the reasonably near future (on the | |||
| order of seconds or minutes). Because clock skews between servers | order of seconds or minutes). Because clock skews between servers | |||
| and clients may be large, servers MAY limit DPoP proof lifetimes by | and clients may be large, servers MAY limit DPoP proof lifetimes by | |||
| using server-provided nonce values containing the time at the server | using server-provided nonce values containing the time at the server | |||
| rather than comparing the client-supplied iat time to the time at the | 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 | server. Nonces created in this way yield the same result even in the | |||
| face of arbitrarily large clock skews. | face of arbitrarily large clock skews. | |||
| Server-provided nonces are an effective means for further reducing | Server-provided nonces are an effective means for further reducing | |||
| the chances for successful DPoP proof replay. Unlike cryptographic | the chances for successful DPoP proof replay. Unlike cryptographic | |||
| nonces, it is acceptable for clients to use the same nonce multiple | nonces, it is acceptable for clients to use the same nonce multiple | |||
| times, and for the server to accept the same nonce multiple times. | times and for the server to accept the same nonce multiple times. As | |||
| As long as the jti value is tracked and duplicates rejected for the | 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. | lifetime of the nonce, there is no additional risk of token replay. | |||
| 11.2. DPoP Proof Pre-Generation | 11.2. DPoP Proof Pre-generation | |||
| An attacker in control of the client can pre-generate DPoP proofs for | An attacker in control of the client can pre-generate DPoP proofs for | |||
| specific endpoints arbitrarily far into the future by choosing the | specific endpoints arbitrarily far into the future by choosing the | |||
| iat value in the DPoP proof to be signed by the proof-of-possession | 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 | 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 | user of the client. The user may pre-generate DPoP proofs to | |||
| exfiltrate from the machine possessing the proof-of-possession key | exfiltrate from the machine possessing the proof-of-possession key | |||
| upon which they were generated and copy them to another machine that | upon which they were generated and copy them to another machine that | |||
| does not possess the key. For instance, a bank employee might pre- | 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 | generate DPoP proofs on a bank computer and then copy them to another | |||
| skipping to change at page 31, line 28 ¶ | skipping to change at line 1399 ¶ | |||
| 11.3. DPoP Nonce Downgrade | 11.3. DPoP Nonce Downgrade | |||
| A server MUST NOT accept any DPoP proofs without the nonce claim when | A server MUST NOT accept any DPoP proofs without the nonce claim when | |||
| a DPoP nonce has been provided to the client. | a DPoP nonce has been provided to the client. | |||
| 11.4. Untrusted Code in the Client Context | 11.4. Untrusted Code in the Client Context | |||
| If an adversary is able to run code in the client's execution | If an adversary is able to run code in the client's execution | |||
| context, the security of DPoP is no longer guaranteed. Common issues | context, the security of DPoP is no longer guaranteed. Common issues | |||
| in web applications leading to the execution of untrusted code are | in web applications leading to the execution of untrusted code are | |||
| cross-site scripting and remote code inclusion attacks. | XSS and remote code inclusion attacks. | |||
| If the private key used for DPoP is stored in such a way that it | 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, | cannot be exported, e.g., in a hardware or software security module, | |||
| the adversary cannot exfiltrate the key and use it to create | the adversary cannot exfiltrate the key and use it to create | |||
| arbitrary DPoP proofs. The adversary can, however, create new DPoP | arbitrary DPoP proofs. The adversary can, however, create new DPoP | |||
| proofs as long as the client is online, and use these proofs | proofs as long as the client is online and uses these proofs | |||
| (together with the respective tokens) either on the victim's device | (together with the respective tokens) either on the victim's device | |||
| or on a device under the attacker's control to send arbitrary | or on a device under the attacker's control to send arbitrary | |||
| requests that will be accepted by servers. | requests that will be accepted by servers. | |||
| To send requests even when the client is offline, an adversary can | To send requests even when the client is offline, an adversary can | |||
| try to pre-compute DPoP proofs using timestamps in the future and | try to pre-compute DPoP proofs using timestamps in the future and | |||
| exfiltrate these together with the access or refresh token. | exfiltrate these together with the access or refresh token. | |||
| An adversary might further try to associate tokens issued from the | An adversary might further try to associate tokens issued from the | |||
| token endpoint with a key pair under the adversary's control. One | token endpoint with a key pair under the adversary's control. One | |||
| skipping to change at page 32, line 20 ¶ | skipping to change at line 1429 ¶ | |||
| This grant needs to be "silent", i.e., not require interaction with | This grant needs to be "silent", i.e., not require interaction with | |||
| the user. With code running in the client's origin, the adversary | the user. With code running in the client's origin, the adversary | |||
| has access to the resulting authorization code and can use it to | has access to the resulting authorization code and can use it to | |||
| associate their own DPoP keys with the tokens returned from the token | associate their own DPoP keys with the tokens returned from the token | |||
| endpoint. The adversary is then able to use the resulting tokens on | endpoint. The adversary is then able to use the resulting tokens on | |||
| their own device even if the client is offline. | their own device even if the client is offline. | |||
| Therefore, protecting clients against the execution of untrusted code | Therefore, protecting clients against the execution of untrusted code | |||
| is extremely important even if DPoP is used. Besides secure coding | is extremely important even if DPoP is used. Besides secure coding | |||
| practices, Content Security Policy [W3C.CSP] can be used as a second | practices, Content Security Policy [W3C.CSP] can be used as a second | |||
| layer of defense against cross-site scripting. | layer of defense against XSS. | |||
| 11.5. Signed JWT Swapping | 11.5. Signed JWT Swapping | |||
| Servers accepting signed DPoP proof JWTs MUST verify that the typ | Servers accepting signed DPoP proof JWTs MUST verify that the typ | |||
| field is dpop+jwt in the headers of the JWTs to ensure that | field is dpop+jwt in the headers of the JWTs to ensure that | |||
| adversaries cannot use JWTs created for other purposes. | adversaries cannot use JWTs created for other purposes. | |||
| 11.6. Signature Algorithms | 11.6. Signature Algorithms | |||
| Implementers MUST ensure that only asymmetric digital signature | Implementers MUST ensure that only asymmetric digital signature | |||
| algorithms (such as ES256) that are deemed secure can be used for | algorithms (such as ES256) that are deemed secure can be used for | |||
| signing DPoP proofs. In particular, the algorithm none MUST NOT be | signing DPoP proofs. In particular, the algorithm none MUST NOT be | |||
| allowed. | allowed. | |||
| 11.7. Request Integrity | 11.7. Request Integrity | |||
| DPoP does not ensure the integrity of the payload or headers of | DPoP does not ensure the integrity of the payload or headers of | |||
| requests. The DPoP proof only contains claims for the HTTP URI and | requests. The DPoP proof only contains claims for the HTTP URI and | |||
| method, but not, for example, the message body or general request | method, but not the message body or general request headers, for | |||
| headers. | example. | |||
| This is an intentional design decision intended to keep DPoP simple | This is an intentional design decision intended to keep DPoP simple | |||
| to use, but as described, makes DPoP potentially susceptible to | to use, but as described, it makes DPoP potentially susceptible to | |||
| replay attacks where an attacker is able to modify message contents | replay attacks where an attacker is able to modify message contents | |||
| and headers. In many setups, the message integrity and | and headers. In many setups, the message integrity and | |||
| confidentiality provided by TLS is sufficient to provide a good level | confidentiality provided by TLS is sufficient to provide a good level | |||
| of protection. | of protection. | |||
| Note: While signatures covering other parts of requests are out of | Note: While signatures covering other parts of requests are out of | |||
| the scope of this specification, additional information to be signed | the scope of this specification, additional information to be signed | |||
| can be added into DPoP proofs. | can be added into DPoP proofs. | |||
| 11.8. Access Token and Public Key Binding | 11.8. Access Token and Public Key Binding | |||
| The binding of the access token to the DPoP public key, which is | The binding of the access token to the DPoP public key, as specified | |||
| specified in Section 6, uses a cryptographic hash of the JWK | in Section 6, uses a cryptographic hash of the JWK representation of | |||
| representation of the public key. It relies on the hash function | the public key. It relies on the hash function having sufficient | |||
| having sufficient second-preimage resistance so as to make it | second-preimage resistance so as to make it computationally | |||
| computationally infeasible to find or create another key that | infeasible to find or create another key that produces to the same | |||
| produces to the same hash output value. The SHA-256 hash function | hash output value. The SHA-256 hash function was used because it | |||
| was used because it meets the aforementioned requirement while being | meets the aforementioned requirement while being widely available. | |||
| widely available. | ||||
| Similarly, the binding of the DPoP proof to the access token uses a | 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 | 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 | 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 | sufficiently unique so as to reliably identify the access token. The | |||
| collision resistance of SHA-256 meets that requirement. | collision resistance of SHA-256 meets that requirement. | |||
| 11.9. Authorization Code and Public Key Binding | 11.9. Authorization Code and Public Key Binding | |||
| Cryptographic binding of the authorization code to the DPoP public | Cryptographic binding of the authorization code to the DPoP public | |||
| key, is specified in Section 10. This binding prevents attacks in | key is specified in Section 10. This binding prevents attacks in | |||
| which the attacker captures the authorization code and creates a DPoP | which the attacker captures the authorization code and creates a DPoP | |||
| proof using a proof-of-possession key other than that held by the | 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 | 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 | ensuring end to end that only the client's DPoP key can be used, this | |||
| prevents captured authorization codes from being exfiltrated and used | prevents captured authorization codes from being exfiltrated and used | |||
| at locations other than the one to which the authorization code was | at locations other than the one to which the authorization code was | |||
| issued. | issued. | |||
| Authorization codes can, for instance, be harvested by attackers from | Authorization codes can, for instance, be harvested by attackers from | |||
| places that the HTTP messages containing them are logged. Even when | places where the HTTP messages containing them are logged. Even when | |||
| efforts are made to make authorization codes one-time-use, in | efforts are made to make authorization codes one-time-use, in | |||
| practice, there is often a time window during which attackers can | practice, there is often a time window during which attackers can | |||
| replay them. For instance, when authorization servers are | replay them. For instance, when authorization servers are | |||
| implemented as scalable replicated services, some replicas may | implemented as scalable replicated services, some replicas may | |||
| temporarily not yet have the information needed to prevent replay. | temporarily not yet have the information needed to prevent replay. | |||
| DPoP binding of the authorization code solves these problems. | DPoP binding of the authorization code solves these problems. | |||
| If an authorization server does not (or cannot) strictly enforce the | If an authorization server does not (or cannot) strictly enforce the | |||
| single-use limitation for authorization codes and an attacker can | single-use limitation for authorization codes and an attacker can | |||
| access the authorization code (and if PKCE is used, the | access the authorization code (and if PKCE is used, the | |||
| code_verifier), the attacker can create a forged token request, | code_verifier), the attacker can create a forged token request, | |||
| binding the resulting token to an attacker-controlled key. For | binding the resulting token to an attacker-controlled key. For | |||
| example, using cross-site scripting, attackers might obtain access to | example, using XSS, attackers might obtain access to the | |||
| the authorization code and PKCE parameters. Use of the dpop_jkt | authorization code and PKCE parameters. Use of the dpop_jkt | |||
| parameter prevents this attack. | parameter prevents this attack. | |||
| The binding of the authorization code to the DPoP public key uses a | 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 | JWK Thumbprint of the public key, just as the access token binding | |||
| does. The same JWK Thumbprint considerations apply. | does. The same JWK Thumbprint considerations apply. | |||
| 11.10. Hash Algorithm Agility | 11.10. Hash Algorithm Agility | |||
| The jkt confirmation method member, the ath JWT claim, and the | The jkt confirmation method member, the ath JWT claim, and the | |||
| dpop_jkt authorization request parameter defined herein all use 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 | output of the SHA-256 hash function as their value. The use of a | |||
| single hash function by this specification was intentional and aimed | single hash function by this specification was intentional and aimed | |||
| at simplicity and avoidance of potential security and | at simplicity and avoidance of potential security and | |||
| interoperability issues arising from common mistakes implementing and | interoperability issues arising from common mistakes implementing and | |||
| deploying parameterized algorithm agility schemes. The use of a | deploying parameterized algorithm agility schemes. However, the use | |||
| different hash function is not precluded, however, if future | of a different hash function is not precluded if future circumstances | |||
| circumstances change making SHA-256 insufficient for the requirements | change and make SHA-256 insufficient for the requirements of this | |||
| of this specification. Should that need arise, it is expected that a | specification. Should that need arise, it is expected that a short | |||
| short specification be produced that updates this one. That | specification will be produced that updates this one. Using the | |||
| specification will likely define, using the output of a then | output of an appropriate hash function as the value, that | |||
| appropriate hash function as the value, a new confirmation method | specification will likely define a new confirmation method member, a | |||
| member, a new JWT claim, and a new authorization request parameter. | new JWT claim, and a new authorization request parameter. These | |||
| These items will be used in place of, or alongside, their respective | items will be used in place of, or alongside, their respective | |||
| counterparts in the same message structures and flows of the larger | counterparts in the same message structures and flows of the larger | |||
| protocol defined by this specification. | protocol defined by this specification. | |||
| 11.11. Binding to Client Identity | 11.11. Binding to Client Identity | |||
| In cases where DPoP is used with client authentication, it is only | In cases where DPoP is used with client authentication, it is only | |||
| bound to authentication by being coincident in the same TLS tunnel. | bound to authentication by being coincident in the same TLS tunnel. | |||
| Since the DPoP proof is not directly cryptographically bound to the | Since the DPoP proof is not directly bound to the authentication | |||
| authentication, it's possible that the authentication or the DPoP | cryptographically, it's possible that the authentication or the DPoP | |||
| messages were copied into the tunnel. While including the URI in the | messages were copied into the tunnel. While including the URI in the | |||
| DPoP can partially mitigate some of this risk, modifying the | DPoP can partially mitigate some of this risk, modifying the | |||
| authentication mechanism to provide cryptographic binding between | authentication mechanism to provide cryptographic binding between | |||
| authentication and DPoP could provide better protection. However, | authentication and DPoP could provide better protection. However, | |||
| providing additional binding with authentication through the | providing additional binding with authentication through the | |||
| modification of authentication mechanisms or other means is beyond | modification of authentication mechanisms or other means is beyond | |||
| the scope of this specification. | the scope of this specification. | |||
| 12. IANA Considerations | 12. IANA Considerations | |||
| 12.1. OAuth Access Token Type Registration | 12.1. OAuth Access Token Types Registration | |||
| This specification requests registration of the following access | IANA has registered the following access token type in the "OAuth | |||
| token type in the "OAuth Access Token Types" registry | Access Token Types" registry [IANA.OAuth.Params] established by | |||
| [IANA.OAuth.Params] established by [RFC6749]. | [RFC6749]. | |||
| * Type name: DPoP | Name: DPoP | |||
| * Additional Token Endpoint Response Parameters: (none) | ||||
| * HTTP Authentication Scheme(s): DPoP | Additional Token Endpoint Response Parameters: (none) | |||
| * Change controller: IETF | ||||
| * Specification document(s): [[ this specification ]] | HTTP Authentication Scheme(s): DPoP | |||
| Change Controller: IETF | ||||
| Reference: RFC 9449 | ||||
| 12.2. OAuth Extensions Error Registration | 12.2. OAuth Extensions Error Registration | |||
| This specification requests registration of the following error | IANA has registered the following error values in the "OAuth | |||
| values in the "OAuth Extensions Error" registry [IANA.OAuth.Params] | Extensions Error" registry [IANA.OAuth.Params] established by | |||
| established by [RFC6749]. | [RFC6749]. | |||
| Invalid DPoP proof: | Invalid DPoP proof: | |||
| * Name: invalid_dpop_proof | Name: invalid_dpop_proof | |||
| * Usage Location: token error response, resource access error | ||||
| response | Usage Location: token error response, resource access error | |||
| * Protocol Extension: Demonstrating Proof of Possession (DPoP) | response | |||
| * Change controller: IETF | ||||
| * Specification document(s): [[ this specification ]] | Protocol Extension: Demonstrating Proof of Possession (DPoP) | |||
| Change Controller: IETF | ||||
| Reference: RFC 9449 | ||||
| Use DPoP nonce: | Use DPoP nonce: | |||
| * Name: use_dpop_nonce | Name: use_dpop_nonce | |||
| * Usage Location: token error response, resource access error | ||||
| response | Usage Location: token error response, resource access error | |||
| * Protocol Extension: Demonstrating Proof of Possession (DPoP) | response | |||
| * Change controller: IETF | ||||
| * Specification document(s): [[ this specification ]] | Protocol Extension: Demonstrating Proof of Possession (DPoP) | |||
| Change Controller: IETF | ||||
| Reference: RFC 9449 | ||||
| 12.3. OAuth Parameters Registration | 12.3. OAuth Parameters Registration | |||
| This specification requests registration of the following | IANA has registered the following authorization request parameter in | |||
| authorization request parameter in the "OAuth Parameters" registry | the "OAuth Parameters" registry [IANA.OAuth.Params] established by | |||
| [IANA.OAuth.Params] established by [RFC6749]. | [RFC6749]. | |||
| * Name: dpop_jkt | Name: dpop_jkt | |||
| * Parameter Usage Location: authorization request | ||||
| * Change Controller: IETF | ||||
| * Reference: [[ Section 10 of this specification ]] | ||||
| 12.4. HTTP Authentication Scheme Registration | Parameter Usage Location: authorization request | |||
| This specification requests registration of the following scheme in | Change Controller: IETF | |||
| the "Hypertext Transfer Protocol (HTTP) Authentication Scheme | ||||
| Registry" [RFC9110][IANA.HTTP.AuthSchemes]: | ||||
| * Authentication Scheme Name: DPoP | Reference: Section 10 of RFC 9449 | |||
| * Reference: [[ Section 7.1 of this specification ]] | ||||
| 12.4. HTTP Authentication Schemes Registration | ||||
| IANA has registered the following scheme in the "HTTP Authentication | ||||
| Schemes" registry [IANA.HTTP.AuthSchemes] established by [RFC9110], | ||||
| Section 16.4.1. | ||||
| Authentication Scheme Name: DPoP | ||||
| Reference: Section 7.1 of RFC 9449 | ||||
| 12.5. Media Type Registration | 12.5. Media Type Registration | |||
| This section registers the application/dpop+jwt media type [RFC2046] | IANA has registered the application/dpop+jwt media type [RFC2046] in | |||
| in the IANA "Media Types" registry [IANA.MediaTypes] in the manner | the "Media Types" registry [IANA.MediaTypes] in the manner described | |||
| described in [RFC6838], which is used to indicate that the content is | in [RFC6838], which is used to indicate that the content is a DPoP | |||
| a DPoP JWT. | JWT. | |||
| * Type name: application | Type name: application | |||
| * Subtype name: dpop+jwt | ||||
| * Required parameters: n/a | Subtype name: dpop+jwt | |||
| * Optional parameters: n/a | ||||
| * Encoding considerations: binary; A DPoP JWT is a JWT; JWT values | Required parameters: n/a | |||
| Optional parameters: n/a | ||||
| Encoding considerations: binary. A DPoP JWT is a JWT; JWT values | ||||
| are encoded as a series of base64url-encoded values (some of which | are encoded as a series of base64url-encoded values (some of which | |||
| may be the empty string) separated by period ('.') characters. | may be the empty string) separated by period ('.') characters. | |||
| * Security considerations: See Section 11 of [[ this specification | ||||
| ]] | Security considerations: See Section 11 of RFC 9449 | |||
| * Interoperability considerations: n/a | ||||
| * Published specification: [[ this specification ]] | Interoperability considerations: n/a | |||
| * Applications that use this media type: Applications using [[ this | ||||
| specification ]] for application-level proof of possession | Published specification: RFC 9449 | |||
| * Fragment identifier considerations: n/a | ||||
| * Additional information: | Applications that use this media type: Applications using RFC 9449 | |||
| - File extension(s): n/a | for application-level proof of possession | |||
| - Macintosh file type code(s): n/a | ||||
| * Person & email address to contact for further information: Michael | Fragment identifier considerations: n/a | |||
| B. Jones, mbj@microsoft.com | ||||
| * Intended usage: COMMON | Additional information: | |||
| * Restrictions on usage: none | ||||
| * Author: Michael B. Jones, mbj@microsoft.com | File extension(s): n/a | |||
| * Change controller: IETF | Macintosh file type code(s): n/a | |||
| * Provisional registration? No | ||||
| Person & email address to contact for further information: Michael | ||||
| B. Jones, michael_b_jones@hotmail.com | ||||
| Intended usage: COMMON | ||||
| Restrictions on usage: none | ||||
| Author: Michael B. Jones, michael_b_jones@hotmail.com | ||||
| Change controller: IETF | ||||
| 12.6. JWT Confirmation Methods Registration | 12.6. JWT Confirmation Methods Registration | |||
| This specification requests registration of the following value in | IANA has registered the following JWT cnf member value in the "JWT | |||
| the IANA "JWT Confirmation Methods" registry [IANA.JWT] for JWT cnf | Confirmation Methods" registry [IANA.JWT] established by [RFC7800]. | |||
| member values established by [RFC7800]. | ||||
| * Confirmation Method Value: jkt | Confirmation Method Value: jkt | |||
| * Confirmation Method Description: JWK SHA-256 Thumbprint | ||||
| * Change Controller: IETF | Confirmation Method Description: JWK SHA-256 Thumbprint | |||
| * Specification Document(s): [[ Section 6 of this specification ]] | ||||
| Change Controller: IETF | ||||
| Reference: Section 6 of RFC 9449 | ||||
| 12.7. JSON Web Token Claims Registration | 12.7. JSON Web Token Claims Registration | |||
| This specification requests registration of the following Claims in | IANA has registered the following Claims in the "JSON Web Token | |||
| the IANA "JSON Web Token Claims" registry [IANA.JWT] established by | Claims" registry [IANA.JWT] established by [RFC7519]. | |||
| [RFC7519]. | ||||
| HTTP method: | HTTP method: | |||
| * Claim Name: htm | Claim Name: htm | |||
| * Claim Description: The HTTP method of the request | ||||
| * Change Controller: IETF | Claim Description: The HTTP method of the request | |||
| * Specification Document(s): [[ Section 4.2 of this specification ]] | ||||
| Change Controller: IETF | ||||
| Reference: Section 4.2 of RFC 9449 | ||||
| HTTP URI: | HTTP URI: | |||
| * Claim Name: htu | Claim Name: htu | |||
| * Claim Description: The HTTP URI of the request (without query and | ||||
| fragment parts) | Claim Description: The HTTP URI of the request (without query and | |||
| * Change Controller: IETF | fragment parts) | |||
| * Specification Document(s): [[ Section 4.2 of this specification ]] | ||||
| Change Controller: IETF | ||||
| Reference: Section 4.2 of RFC 9449 | ||||
| Access token hash: | Access token hash: | |||
| * Claim Name: ath | Claim Name: ath | |||
| * Claim Description: The base64url encoded SHA-256 hash of the ASCII | ||||
| encoding of the associated access token's value | ||||
| * Change Controller: IETF | ||||
| * Specification Document(s): [[ Section 4.2 of this specification ]] | ||||
| 12.7.1. "nonce" Registry Update | Claim Description: The base64url-encoded SHA-256 hash of the | |||
| ASCII encoding of the associated access token's value | ||||
| Change Controller: IETF | ||||
| Reference: Section 4.2 of RFC 9449 | ||||
| 12.7.1. "nonce" Registration Update | ||||
| The Internet Security Glossary [RFC4949] provides a useful definition | The Internet Security Glossary [RFC4949] provides a useful definition | |||
| of nonce as a random or non-repeating value that is included in data | of nonce as a random or non-repeating value that is included in data | |||
| exchanged by a protocol, usually for the purpose of guaranteeing | exchanged by a protocol, usually for the purpose of guaranteeing | |||
| liveness and thus detecting and protecting against replay attacks. | liveness and thus detecting and protecting against replay attacks. | |||
| However, the initial registration of the nonce claim by [OpenID.Core] | However, the initial registration of the nonce claim by [OpenID.Core] | |||
| used language that was contextually specific to that application, | used language that was contextually specific to that application, | |||
| which was potentially limiting to its general applicability. | which was potentially limiting to its general applicability. | |||
| This specification therefore requests that the entry for nonce in the | Therefore, IANA has updated the entry for nonce in the "JSON Web | |||
| IANA "JSON Web Token Claims" registry [IANA.JWT] be updated as | Token Claims" registry [IANA.JWT] with an expanded definition to | |||
| follows to reflect that the claim can be used appropriately in other | reflect that the claim can be used appropriately in other contexts | |||
| contexts. | and with the addition of this document as a reference, as follows. | |||
| * Claim Name: nonce | Claim Name: nonce | |||
| * Claim Description: Value used to associate a Client session with | ||||
| an ID Token (MAY also be used for nonce values in other | ||||
| applications of JWTs) | ||||
| * Change Controller: OpenID Foundation Artifact Binding Working | ||||
| Group - openid-specs-ab@lists.openid.net | ||||
| * Specification Document(s): Section 2 of [OpenID.Core] and [[ this | ||||
| specification ]] | ||||
| 12.8. HTTP Message Header Field Names Registration | Claim Description: Value used to associate a Client session with an | |||
| ID Token (MAY also be used for nonce values in other applications | ||||
| of JWTs) | ||||
| This document specifies the following HTTP header fields, | Change Controller: OpenID Foundation Artifact Binding Working Group, | |||
| registration of which is requested in the "Hypertext Transfer | openid-specs-ab@lists.openid.net | |||
| Protocol (HTTP) Field Name Registry" registry | ||||
| [RFC9110][IANA.HTTP.Fields]: | ||||
| * Field name: DPoP | Specification Document(s): Section 2 of [OpenID.Core] and RFC 9449 | |||
| * Status: permanent | 12.8. Hypertext Transfer Protocol (HTTP) Field Name Registration | |||
| * Specification document: [[ this specification ]] | IANA has registered the following HTTP header fields, as specified by | |||
| this document, in the "Hypertext Transfer Protocol (HTTP) Field Name | ||||
| Registry" [IANA.HTTP.Fields] established by [RFC9110]: | ||||
| * Field name: DPoP-Nonce | DPoP: | |||
| * Status: permanent | Field Name: DPoP | |||
| * Specification document: [[ this specification ]] | Status: permanent | |||
| Reference: RFC 9449 | ||||
| DPoP-Nonce: | ||||
| Field Name: DPoP-Nonce | ||||
| Status: permanent | ||||
| Reference: RFC 9449 | ||||
| 12.9. OAuth Authorization Server Metadata Registration | 12.9. OAuth Authorization Server Metadata Registration | |||
| This specification requests registration of the following value in | IANA has registered the following value in the "OAuth Authorization | |||
| the IANA "OAuth Authorization Server Metadata" registry | Server Metadata" registry [IANA.OAuth.Params] established by | |||
| [IANA.OAuth.Params] established by [RFC8414]. | [RFC8414]. | |||
| * Metadata Name: dpop_signing_alg_values_supported | Metadata Name: dpop_signing_alg_values_supported | |||
| * Metadata Description: JSON array containing a list of the JWS | ||||
| Metadata Description: JSON array containing a list of the JWS | ||||
| algorithms supported for DPoP proof JWTs | algorithms supported for DPoP proof JWTs | |||
| * Change Controller: IETF | ||||
| * Specification Document(s): [[ Section 5.1 of this specification ]] | Change Controller: IETF | |||
| Reference: Section 5.1 of RFC 9449 | ||||
| 12.10. OAuth Dynamic Client Registration Metadata | 12.10. OAuth Dynamic Client Registration Metadata | |||
| This specification requests registration of the following value in | IANA has registered the following value in the IANA "OAuth Dynamic | |||
| the IANA "OAuth Dynamic Client Registration Metadata" registry | Client Registration Metadata" registry [IANA.OAuth.Params] | |||
| [IANA.OAuth.Params] established by [RFC7591]. | established by [RFC7591]. | |||
| * Metadata Name: dpop_bound_access_tokens | Client Metadata Name: dpop_bound_access_tokens | |||
| * Metadata Description: Boolean value specifying whether the client | ||||
| always uses DPoP for token requests | ||||
| * Change Controller: IETF | ||||
| * Specification Document(s): [[ Section 5.2 of this specification ]] | ||||
| 13. Normative References | Client Metadata Description: Boolean value specifying whether the | |||
| client always uses DPoP for token requests | ||||
| Change Controller: IETF | ||||
| Reference: Section 5.2 of RFC 9449 | ||||
| 13. References | ||||
| 13.1. Normative References | ||||
| [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate | [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate | |||
| Requirement Levels", BCP 14, RFC 2119, | Requirement Levels", BCP 14, RFC 2119, | |||
| DOI 10.17487/RFC2119, March 1997, | DOI 10.17487/RFC2119, March 1997, | |||
| <https://www.rfc-editor.org/info/rfc2119>. | <https://www.rfc-editor.org/info/rfc2119>. | |||
| [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform | [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform | |||
| Resource Identifier (URI): Generic Syntax", STD 66, | Resource Identifier (URI): Generic Syntax", STD 66, | |||
| RFC 3986, DOI 10.17487/RFC3986, January 2005, | RFC 3986, DOI 10.17487/RFC3986, January 2005, | |||
| <https://www.rfc-editor.org/info/rfc3986>. | <https://www.rfc-editor.org/info/rfc3986>. | |||
| skipping to change at page 40, line 15 ¶ | skipping to change at line 1856 ¶ | |||
| [RFC7800] Jones, M., Bradley, J., and H. Tschofenig, "Proof-of- | [RFC7800] Jones, M., Bradley, J., and H. Tschofenig, "Proof-of- | |||
| Possession Key Semantics for JSON Web Tokens (JWTs)", | Possession Key Semantics for JSON Web Tokens (JWTs)", | |||
| RFC 7800, DOI 10.17487/RFC7800, April 2016, | RFC 7800, DOI 10.17487/RFC7800, April 2016, | |||
| <https://www.rfc-editor.org/info/rfc7800>. | <https://www.rfc-editor.org/info/rfc7800>. | |||
| [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC | [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC | |||
| 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, | 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, | |||
| May 2017, <https://www.rfc-editor.org/info/rfc8174>. | May 2017, <https://www.rfc-editor.org/info/rfc8174>. | |||
| [SHS] National Institute of Standards and Technology, "Secure | [SHS] National Institute of Standards and Technology, "Secure | |||
| Hash Standard (SHS)", FIPS PUB 180-4, August 2015, | Hash Standard (SHS)", FIPS PUB 180-4, | |||
| <https://nvlpubs.nist.gov/nistpubs/FIPS/ | DOI 10.6028/NIST.FIPS.180-4, August 2015, | |||
| NIST.FIPS.180-4.pdf>. | <http://dx.doi.org/10.6028/NIST.FIPS.180-4>. | |||
| 14. Informative References | 13.2. Informative References | |||
| [BREACH] "CVE-2013-3587", <https://cve.mitre.org/cgi-bin/ | [BREACH] CVE, "CVE-2013-3587", <https://cve.mitre.org/cgi-bin/ | |||
| cvename.cgi?name=CVE-2013-3587>. | cvename.cgi?name=CVE-2013-3587>. | |||
| [CRIME] "CVE-2012-4929", <https://cve.mitre.org/cgi-bin/ | ||||
| cvename.cgi?name=cve-2012-4929>. | ||||
| [Cloudbleed] | [Cloudbleed] | |||
| "Incident report on memory leak caused by Cloudflare | Graham-Cumming, J., "Incident report on memory leak caused | |||
| parser bug", <https://blog.cloudflare.com/incident-report- | by Cloudflare parser bug", February 2017, | |||
| on-memory-leak-caused-by-cloudflare-parser-bug/>. | <https://blog.cloudflare.com/incident-report-on-memory- | |||
| leak-caused-by-cloudflare-parser-bug/>. | ||||
| [CRIME] CVE, "CVE-2012-4929", <https://cve.mitre.org/cgi-bin/ | ||||
| cvename.cgi?name=cve-2012-4929>. | ||||
| [GitHub.Tokens] | [GitHub.Tokens] | |||
| "Security alert: Attack campaign involving stolen OAuth | Hanley, M., "Security alert: Attack campaign involving | |||
| user tokens issued to two third-party integrators", | stolen OAuth user tokens issued to two third-party | |||
| <https://github.blog/2022-04-15-security-alert-stolen- | integrators", April 2022, <https://github.blog/2022-04-15- | |||
| oauth-user-tokens/>. | security-alert-stolen-oauth-user-tokens/>. | |||
| [Heartbleed] | [Heartbleed] | |||
| "CVE-2014-0160", <https://cve.mitre.org/cgi-bin/ | "CVE-2014-0160", <https://cve.mitre.org/cgi-bin/ | |||
| cvename.cgi?name=cve-2014-0160>. | cvename.cgi?name=cve-2014-0160>. | |||
| [I-D.ietf-oauth-security-topics] | ||||
| Lodderstedt, T., Bradley, J., Labunets, A., and D. Fett, | ||||
| "OAuth 2.0 Security Best Current Practice", Work in | ||||
| Progress, Internet-Draft, draft-ietf-oauth-security- | ||||
| topics-22, 13 March 2023, | ||||
| <https://datatracker.ietf.org/doc/html/draft-ietf-oauth- | ||||
| security-topics-22>. | ||||
| [I-D.ietf-oauth-token-binding] | ||||
| Jones, M., Campbell, B., Bradley, J., and W. Denniss, | ||||
| "OAuth 2.0 Token Binding", Work in Progress, Internet- | ||||
| Draft, draft-ietf-oauth-token-binding-08, 19 October 2018, | ||||
| <https://datatracker.ietf.org/doc/html/draft-ietf-oauth- | ||||
| token-binding-08>. | ||||
| [IANA.HTTP.AuthSchemes] | [IANA.HTTP.AuthSchemes] | |||
| IANA, "Hypertext Transfer Protocol (HTTP) Authentication | IANA, "Hypertext Transfer Protocol (HTTP) Authentication | |||
| Scheme Registry", | Scheme Registry", | |||
| <https://www.iana.org/assignments/http-authschemes>. | <https://www.iana.org/assignments/http-authschemes/>. | |||
| [IANA.HTTP.Fields] | [IANA.HTTP.Fields] | |||
| IANA, "Hypertext Transfer Protocol (HTTP) Field Name | IANA, "Hypertext Transfer Protocol (HTTP) Field Name | |||
| Registry", <https://www.iana.org/assignments/http-fields/ | Registry", | |||
| http-fields.xhtml>. | <https://www.iana.org/assignments/http-fields/>. | |||
| [IANA.JOSE.ALGS] | [IANA.JOSE.ALGS] | |||
| IANA, "JSON Web Signature and Encryption Algorithms", | IANA, "JSON Web Signature and Encryption Algorithms", | |||
| <https://www.iana.org/assignments/jose/jose.xhtml#web- | <https://www.iana.org/assignments/jose/>. | |||
| signature-encryption-algorithms>. | ||||
| [IANA.JWT] IANA, "JSON Web Token Claims", | [IANA.JWT] IANA, "JSON Web Token Claims", | |||
| <https://www.iana.org/assignments/jwt>. | <https://www.iana.org/assignments/jwt/>. | |||
| [IANA.MediaTypes] | [IANA.MediaTypes] | |||
| IANA, "Media Types", | IANA, "Media Types", | |||
| <https://www.iana.org/assignments/media-types>. | <https://www.iana.org/assignments/media-types/>. | |||
| [IANA.OAuth.Params] | [IANA.OAuth.Params] | |||
| IANA, "OAuth Parameters", | IANA, "OAuth Parameters", | |||
| <https://www.iana.org/assignments/oauth-parameters>. | <https://www.iana.org/assignments/oauth-parameters/>. | |||
| [OpenID.Core] | [OpenID.Core] | |||
| Sakimura, N., Bradley, J., Jones, M.B., Medeiros, B.d., | Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and | |||
| and C. Mortimore, "OpenID Connect Core 1.0", November | C. Mortimore, "OpenID Connect Core 1.0 incorporating | |||
| 2014, | errata set 1", November 2014, | |||
| <https://openid.net/specs/openid-connect-core-1_0.html>. | <https://openid.net/specs/openid-connect-core-1_0.html>. | |||
| [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail | [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail | |||
| Extensions (MIME) Part Two: Media Types", RFC 2046, | Extensions (MIME) Part Two: Media Types", RFC 2046, | |||
| DOI 10.17487/RFC2046, November 1996, | DOI 10.17487/RFC2046, November 1996, | |||
| <https://www.rfc-editor.org/info/rfc2046>. | <https://www.rfc-editor.org/info/rfc2046>. | |||
| [RFC4122] Leach, P., Mealling, M., and R. Salz, "A Universally | [RFC4122] Leach, P., Mealling, M., and R. Salz, "A Universally | |||
| Unique IDentifier (UUID) URN Namespace", RFC 4122, | Unique IDentifier (UUID) URN Namespace", RFC 4122, | |||
| DOI 10.17487/RFC4122, July 2005, | DOI 10.17487/RFC4122, July 2005, | |||
| skipping to change at page 43, line 20 ¶ | skipping to change at line 1988 ¶ | |||
| [RFC9110] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, | [RFC9110] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, | |||
| Ed., "HTTP Semantics", STD 97, RFC 9110, | Ed., "HTTP Semantics", STD 97, RFC 9110, | |||
| DOI 10.17487/RFC9110, June 2022, | DOI 10.17487/RFC9110, June 2022, | |||
| <https://www.rfc-editor.org/info/rfc9110>. | <https://www.rfc-editor.org/info/rfc9110>. | |||
| [RFC9126] Lodderstedt, T., Campbell, B., Sakimura, N., Tonge, D., | [RFC9126] Lodderstedt, T., Campbell, B., Sakimura, N., Tonge, D., | |||
| and F. Skokan, "OAuth 2.0 Pushed Authorization Requests", | and F. Skokan, "OAuth 2.0 Pushed Authorization Requests", | |||
| RFC 9126, DOI 10.17487/RFC9126, September 2021, | RFC 9126, DOI 10.17487/RFC9126, September 2021, | |||
| <https://www.rfc-editor.org/info/rfc9126>. | <https://www.rfc-editor.org/info/rfc9126>. | |||
| [W3C.CSP] West, M., "Content Security Policy Level 3", World Wide | [SECURITY-TOPICS] | |||
| Web Consortium Working Draft WD-CSP3-20181015, 15 October | Lodderstedt, T., Bradley, J., Labunets, A., and D. Fett, | |||
| 2018, <https://www.w3.org/TR/2018/WD-CSP3-20181015/>. | "OAuth 2.0 Security Best Current Practice", Work in | |||
| Progress, Internet-Draft, draft-ietf-oauth-security- | ||||
| topics-23, 5 June 2023, | ||||
| <https://datatracker.ietf.org/doc/html/draft-ietf-oauth- | ||||
| security-topics-23>. | ||||
| [TOKEN-BINDING] | ||||
| Jones, M., Campbell, B., Bradley, J., and W. Denniss, | ||||
| "OAuth 2.0 Token Binding", Work in Progress, Internet- | ||||
| Draft, draft-ietf-oauth-token-binding-08, 19 October 2018, | ||||
| <https://datatracker.ietf.org/doc/html/draft-ietf-oauth- | ||||
| token-binding-08>. | ||||
| [W3C.CSP] West, M., "Content Security Policy Level 3", W3C Working | ||||
| Draft, July 2023, <https://www.w3.org/TR/CSP3/>. | ||||
| [W3C.WebCryptoAPI] | [W3C.WebCryptoAPI] | |||
| Watson, M., "Web Cryptography API", World Wide Web | Watson, M., "Web Cryptography API", W3C Recommendation, | |||
| Consortium Recommendation REC-WebCryptoAPI-20170126, 26 | ||||
| January 2017, | January 2017, | |||
| <https://www.w3.org/TR/2017/REC-WebCryptoAPI-20170126>. | <https://www.w3.org/TR/2017/REC-WebCryptoAPI-20170126>. | |||
| [WHATWG.Fetch] | [WHATWG.Fetch] | |||
| WHATWG, "Fetch Living Standard", May 2022, | WHATWG, "Fetch Living Standard", July 2023, | |||
| <https://fetch.spec.whatwg.org/>. | <https://fetch.spec.whatwg.org/>. | |||
| Appendix A. Acknowledgements | Acknowledgements | |||
| We would like to thank Brock Allen, Annabelle Backman, Spencer | We would like to thank Brock Allen, Annabelle Backman, Dominick | |||
| Balogh, Dominick Baier, Vittorio Bertocci, Jeff Corrigan, Domingos | Baier, Spencer Balogh, Vittorio Bertocci, Jeff Corrigan, Domingos | |||
| Creado, Andrii Deinega, William Denniss, Vladimir Dzhuvinov, Mike | Creado, Philippe De Ryck, Andrii Deinega, William Denniss, Vladimir | |||
| Engan, Nikos Fotiou, Mark Haine, Dick Hardt, Joseph Heenan, Bjorn | Dzhuvinov, Mike Engan, Nikos Fotiou, Mark Haine, Dick Hardt, Joseph | |||
| Hjelm, Jacob Ideskog, Jared Jennings, Benjamin Kaduk, Pieter | Heenan, Bjorn Hjelm, Jacob Ideskog, Jared Jennings, Benjamin Kaduk, | |||
| Kasselman, Neil Madden, Rohan Mahy, Karsten Meyer zu Selhausen, | Pieter Kasselman, Neil Madden, Rohan Mahy, Karsten Meyer zu | |||
| Nicolas Mora, Steinar Noem, Mark Nottingham, Rob Otto, Aaron Parecki, | Selhausen, Nicolas Mora, Steinar Noem, Mark Nottingham, Rob Otto, | |||
| Michael Peck, Roberto Polli, Paul Querna, Justin Richer, Joseph | Aaron Parecki, Michael Peck, Roberto Polli, Paul Querna, Justin | |||
| Salowey, Rifaat Shekh-Yusef, Filip Skokan, Dmitry Telegin, Dave | Richer, Joseph Salowey, Rifaat Shekh-Yusef, Filip Skokan, Dmitry | |||
| Tonge, Jim Willeke, Philippe De Ryck, and others (please let us know, | Telegin, Dave Tonge, Jim Willeke, and others for their valuable | |||
| if you've been mistakenly omitted) for their valuable input, feedback | input, feedback, and general support of this work. | |||
| and general support of this work. | ||||
| This document originated from discussions at the 4th OAuth Security | This document originated from discussions at the 4th OAuth Security | |||
| Workshop in Stuttgart, Germany. We thank the organizers of this | Workshop in Stuttgart, Germany. We thank the organizers of this | |||
| workshop (Ralf Kusters, Guido Schmitz). | workshop (Ralf Küsters and Guido Schmitz). | |||
| Appendix B. Document History | ||||
| [[ To be removed from the final specification ]] | ||||
| -16 | ||||
| * Per suggestion of the registry's designated expert, change | ||||
| "resource error response" to "resource access error response" for | ||||
| location of the two items in the "OAuth Extensions Error | ||||
| Registration" section | ||||
| -15 | ||||
| * Editorial updates from IESG review/ballot | ||||
| * Mike Jones and Daniel Fett with new email/organization info | ||||
| -14 | ||||
| * Add sec considerations sub-section about binding to client | ||||
| identity | ||||
| * Explicitly say that nonces must be unpredictable | ||||
| * Change to a numbered list in 'Checking DPoP Proofs' | ||||
| * Editorial adjustments | ||||
| * Incorporated HTTP header field definition and RFC 8792 '\' line | ||||
| wrapping suggestions by Mark Nottingham | ||||
| -13 | ||||
| * Editorial updates/fixes | ||||
| * Make sure RFC7519 is a normative reference | ||||
| -12 | ||||
| * Updates from Roman Danyliw's AD review | ||||
| * DPoP-Nonce now included in HTTP header field registration request | ||||
| * Fixed section reference to URI Scheme-Based Normalization | ||||
| * Attempt to better describe the rationale for SHA-256 only and | ||||
| expectations for how hash algorithm agility would be achieved if | ||||
| needed in the future | ||||
| * Elaborate on the use of multiple WWW-Authenticate challenges by | ||||
| protected resources | ||||
| * Fix access token request examples that were missing a client_id | ||||
| -11 | ||||
| * Updates addressing outstanding shepherd review comments per side | ||||
| meeting discussions at IETF 114 | ||||
| * Added more explanation of the PAR considerations | ||||
| * Added parenthetical remark "(such as ES256)" to Signature | ||||
| Algorithms subsection | ||||
| * Added more explanation for ath | ||||
| * Added a reference to RFC8725 in mention of explicit JWT typing | ||||
| -10 | ||||
| * Updates addressing some shepherd review comments | ||||
| * Update HTTP references as RFCs 723x have been superseded by RFC | ||||
| 9110 | ||||
| * Editorial fixes | ||||
| * Added some clarifications, etc. around nonce | ||||
| * Added client considerations subsection | ||||
| * Use bullets rather than numbers in Checking DPoP Proofs so as not | ||||
| to imply specific order | ||||
| * Added notes/reminders about browser-based client applications | ||||
| using CORS needing access to response headers | ||||
| * Added a JWT claims registry update request for "nonce" to (better) | ||||
| allow for more general use in other contexts | ||||
| -09 | ||||
| * Add note/reminder about browser-based client applications using | ||||
| CORS needing access to response headers. | ||||
| * Fixed typo | ||||
| -08 | ||||
| * Lots of editorial updates from WGLC feedback | ||||
| * Further clarify that either iat or nonce can be used alone in | ||||
| validating the timeliness of the proof and somewhat de-emphasize | ||||
| jti tracking | ||||
| -07 | ||||
| * Registered the application/dpop+jwt media type. | ||||
| * Editorial updates/clarifications based on review feedback. | ||||
| * Added "(on the order of seconds or minutes)" to somewhat qualify | ||||
| "relatively brief period" and "reasonably near future" and give a | ||||
| general idea of expected timeframe without being overly | ||||
| prescriptive. | ||||
| * Added a step to Section 4.3 to reiterate that the jwk header | ||||
| cannot have a private key. | ||||
| -06 | ||||
| * Editorial updates and fixes | ||||
| * Changed name of client metadata parameter to | ||||
| dpop_bound_access_tokens | ||||
| -05 | ||||
| * Added Authorization Code binding via the dpop_jkt parameter. | ||||
| * Described the authorization code reuse attack and how dpop_jkt | ||||
| mitigates it. | ||||
| * Enhanced description of DPoP proof expiration checking. | ||||
| * Described nonce storage requirements and how nonce mismatches and | ||||
| missing nonces are self-correcting. | ||||
| * Specified the use of the use_dpop_nonce error for missing and | ||||
| mismatched nonce values. | ||||
| * Specified that authorization servers use 400 (Bad Request) errors | ||||
| to supply nonces and resource servers use 401 (Unauthorized) | ||||
| errors to do so. | ||||
| * Added a bit more about ath and pre-generated proofs to the | ||||
| security considerations. | ||||
| * Mentioned confirming the DPoP binding of the access token in the | ||||
| list in Section 4.3. | ||||
| * Added the always_uses_dpop client registration metadata parameter. | ||||
| * Described the relationship between DPoP and Pushed Authorization | ||||
| Requests (PAR). | ||||
| * Updated references for drafts that are now RFCs. | ||||
| -04 | ||||
| * Added the option for a server-provided nonce in the DPoP proof. | ||||
| * Registered the invalid_dpop_proof and use_dpop_nonce error codes. | ||||
| * Removed fictitious uses of realm from the examples, as they added | ||||
| no value. | ||||
| * State that if the introspection response has a token_type, it has | ||||
| to be DPoP. | ||||
| * Mention that RFC7235 allows multiple authentication schemes in | ||||
| WWW-Authenticate with a 401. | ||||
| * Editorial fixes. | ||||
| -03 | ||||
| * Add an access token hash (ath) claim to the DPoP proof when used | ||||
| in conjunction with the presentation of an access token for | ||||
| protected resource access | ||||
| * add Untrusted Code in the Client Context section to security | ||||
| considerations | ||||
| * Editorial updates and fixes | ||||
| -02 | ||||
| * Lots of editorial updates and additions including expanding on the | ||||
| objectives, better defining the key confirmation representations, | ||||
| example updates and additions, better describing mixed bearer/dpop | ||||
| token type deployments, clarify RT binding only being done for | ||||
| public clients and why, more clearly allow for a bound RT but with | ||||
| bearer AT, explain/justify the choice of SHA-256 for key binding, | ||||
| and more | ||||
| * Require that a protected resource supporting bearer and DPoP at | ||||
| the same time must reject an access token received as bearer, if | ||||
| that token is DPoP-bound | ||||
| * Remove the case-insensitive qualification on the htm claim check | ||||
| * Relax the jti tracking requirements a bit and qualify it by URI | ||||
| -01 | ||||
| * Editorial updates | ||||
| * Attempt to more formally define the DPoP Authorization header | ||||
| scheme | ||||
| * Define the 401/WWW-Authenticate challenge | ||||
| * Added invalid_dpop_proof error code for DPoP errors in token | ||||
| request | ||||
| * Fixed up and added to the IANA section | ||||
| * Added dpop_signing_alg_values_supported authorization server | ||||
| metadata | ||||
| * Moved the Acknowledgements into an Appendix and added a bunch of | ||||
| names (best effort) | ||||
| -00 [[ Working Group Draft ]] | ||||
| * Working group draft | ||||
| -04 | ||||
| * Update OAuth MTLS reference to RFC 8705 | ||||
| * Use the newish RFC v3 XML and HTML format | ||||
| -03 | ||||
| * rework the text around uniqueness requirements on the jti claim in | ||||
| the DPoP proof JWT | ||||
| * make tokens a bit smaller by using htm, htu, and jkt rather than | ||||
| http_method, http_uri, and jkt#S256 respectively | ||||
| * more explicit recommendation to use mTLS if that is available | ||||
| * added David Waite as co-author | ||||
| * editorial updates | ||||
| -02 | ||||
| * added normalization rules for URIs | ||||
| * removed distinction between proof and binding | ||||
| * "jwk" header again used instead of "cnf" claim in DPoP proof | ||||
| * renamed "Bearer-DPoP" token type to "DPoP" | ||||
| * removed ability for key rotation | ||||
| * added security considerations on request integrity | ||||
| * explicit advice on extending DPoP proofs to sign other parts of | ||||
| the HTTP messages | ||||
| * only use the jkt#S256 in ATs | ||||
| * iat instead of exp in DPoP proof JWTs | ||||
| * updated guidance on token_type evaluation | ||||
| -01 | ||||
| * fixed inconsistencies | ||||
| * moved binding and proof messages to headers instead of parameters | ||||
| * extracted and unified definition of DPoP JWTs | ||||
| * improved description | ||||
| -00 | ||||
| * first draft | ||||
| Authors' Addresses | Authors' Addresses | |||
| Daniel Fett | Daniel Fett | |||
| Authlete | Authlete | |||
| Email: mail@danielfett.de | Email: mail@danielfett.de | |||
| Brian Campbell | Brian Campbell | |||
| Ping Identity | Ping Identity | |||
| Email: bcampbell@pingidentity.com | Email: bcampbell@pingidentity.com | |||
| John Bradley | John Bradley | |||
| Yubico | Yubico | |||
| Email: ve7jtb@ve7jtb.com | Email: ve7jtb@ve7jtb.com | |||
| Torsten Lodderstedt | Torsten Lodderstedt | |||
| yes.com | Tuconic | |||
| Email: torsten@lodderstedt.net | Email: torsten@lodderstedt.net | |||
| Michael Jones | Michael Jones | |||
| independent | Self-Issued Consulting | |||
| Email: michael_b_jones@hotmail.com | Email: michael_b_jones@hotmail.com | |||
| URI: https://self-issued.info/ | URI: https://self-issued.info/ | |||
| David Waite | David Waite | |||
| Ping Identity | Ping Identity | |||
| Email: david@alkaline-solutions.com | Email: david@alkaline-solutions.com | |||
| End of changes. 205 change blocks. | ||||
| 875 lines changed or deleted | 725 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. | ||||