draft-ietf-gnap-core-protocol-05.txt | draft-ietf-gnap-core-protocol-06.txt | |||
---|---|---|---|---|
GNAP J. Richer, Ed. | GNAP J. Richer, Ed. | |||
Internet-Draft Bespoke Engineering | Internet-Draft Bespoke Engineering | |||
Intended status: Standards Track A. Parecki | Intended status: Standards Track A. Parecki | |||
Expires: 30 October 2021 Okta | Expires: 13 January 2022 Okta | |||
F. Imbault | F. Imbault | |||
acert.io | acert.io | |||
28 April 2021 | 12 July 2021 | |||
Grant Negotiation and Authorization Protocol | Grant Negotiation and Authorization Protocol | |||
draft-ietf-gnap-core-protocol-05 | draft-ietf-gnap-core-protocol-06 | |||
Abstract | Abstract | |||
GNAP defines a mechanism for delegating authorization to a piece of | GNAP defines a mechanism for delegating authorization to a piece of | |||
software, and conveying that delegation to the software. This | software, and conveying that delegation to the software. This | |||
delegation can include access to a set of APIs as well as information | delegation can include access to a set of APIs as well as information | |||
passed directly to the software. | passed directly to the software. | |||
Status of This Memo | Status of This Memo | |||
skipping to change at page 1, line 36 ¶ | skipping to change at page 1, line 36 ¶ | |||
Internet-Drafts are working documents of the Internet Engineering | Internet-Drafts are working documents of the Internet Engineering | |||
Task Force (IETF). Note that other groups may also distribute | Task Force (IETF). Note that other groups may also distribute | |||
working documents as Internet-Drafts. The list of current Internet- | working documents as Internet-Drafts. The list of current Internet- | |||
Drafts is at https://datatracker.ietf.org/drafts/current/. | Drafts is at https://datatracker.ietf.org/drafts/current/. | |||
Internet-Drafts are draft documents valid for a maximum of six months | Internet-Drafts are draft documents valid for a maximum of six months | |||
and may be updated, replaced, or obsoleted by other documents at any | and may be updated, replaced, or obsoleted by other documents at any | |||
time. It is inappropriate to use Internet-Drafts as reference | time. It is inappropriate to use Internet-Drafts as reference | |||
material or to cite them other than as "work in progress." | material or to cite them other than as "work in progress." | |||
This Internet-Draft will expire on 30 October 2021. | This Internet-Draft will expire on 13 January 2022. | |||
Copyright Notice | Copyright Notice | |||
Copyright (c) 2021 IETF Trust and the persons identified as the | Copyright (c) 2021 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 (https://trustee.ietf.org/ | |||
license-info) in effect on the date of publication of this document. | license-info) in effect on the date of publication of this document. | |||
Please review these documents carefully, as they describe your rights | Please review these documents carefully, as they describe your rights | |||
and restrictions with respect to this document. Code Components | and restrictions with respect to this document. Code Components | |||
extracted from this document must include Simplified BSD License text | extracted from this document must include Simplified BSD License text | |||
as described in Section 4.e of the Trust Legal Provisions and are | as described in Section 4.e of the Trust Legal Provisions and are | |||
provided without warranty as described in the Simplified BSD License. | provided without warranty as described in the Simplified BSD License. | |||
Table of Contents | Table of Contents | |||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 | 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 | |||
1.1. Terminology . . . . . . . . . . . . . . . . . . . . . . . 5 | 1.1. Terminology . . . . . . . . . . . . . . . . . . . . . . . 5 | |||
1.2. Roles . . . . . . . . . . . . . . . . . . . . . . . . . . 5 | 1.2. Roles . . . . . . . . . . . . . . . . . . . . . . . . . . 5 | |||
1.3. Elements . . . . . . . . . . . . . . . . . . . . . . . . 7 | 1.3. Elements . . . . . . . . . . . . . . . . . . . . . . . . 8 | |||
1.4. Sequences . . . . . . . . . . . . . . . . . . . . . . . . 8 | 1.4. Sequences . . . . . . . . . . . . . . . . . . . . . . . . 9 | |||
1.4.1. Redirect-based Interaction . . . . . . . . . . . . . 11 | 1.4.1. Redirect-based Interaction . . . . . . . . . . . . . 12 | |||
1.4.2. User-code Interaction . . . . . . . . . . . . . . . . 14 | 1.4.2. User-code Interaction . . . . . . . . . . . . . . . . 15 | |||
1.4.3. Asynchronous Authorization . . . . . . . . . . . . . 16 | 1.4.3. Asynchronous Authorization . . . . . . . . . . . . . 17 | |||
1.4.4. Software-only Authorization . . . . . . . . . . . . . 18 | 1.4.4. Software-only Authorization . . . . . . . . . . . . . 19 | |||
1.4.5. Refreshing an Expired Access Token . . . . . . . . . 19 | 1.4.5. Refreshing an Expired Access Token . . . . . . . . . 20 | |||
1.4.6. Requesting User Information . . . . . . . . . . . . . 21 | 1.4.6. Requesting User Information . . . . . . . . . . . . . 22 | |||
2. Requesting Access . . . . . . . . . . . . . . . . . . . . . . 22 | 2. Requesting Access . . . . . . . . . . . . . . . . . . . . . . 23 | |||
2.1. Requesting Access to Resources . . . . . . . . . . . . . 24 | 2.1. Requesting Access to Resources . . . . . . . . . . . . . 25 | |||
2.1.1. Requesting a Single Access Token . . . . . . . . . . 24 | 2.1.1. Requesting a Single Access Token . . . . . . . . . . 25 | |||
2.1.2. Requesting Multiple Access Tokens . . . . . . . . . . 27 | 2.1.2. Requesting Multiple Access Tokens . . . . . . . . . . 28 | |||
2.2. Requesting Subject Information . . . . . . . . . . . . . 29 | 2.2. Requesting Subject Information . . . . . . . . . . . . . 30 | |||
2.3. Identifying the Client Instance . . . . . . . . . . . . . 30 | 2.3. Identifying the Client Instance . . . . . . . . . . . . . 31 | |||
2.3.1. Identifying the Client Instance by Reference . . . . 31 | 2.3.1. Identifying the Client Instance by Reference . . . . 32 | |||
2.3.2. Providing Displayable Client Instance Information . . 32 | 2.3.2. Providing Displayable Client Instance Information . . 33 | |||
2.3.3. Authenticating the Client Instance . . . . . . . . . 33 | 2.3.3. Authenticating the Client Instance . . . . . . . . . 33 | |||
2.4. Identifying the User . . . . . . . . . . . . . . . . . . 33 | 2.4. Identifying the User . . . . . . . . . . . . . . . . . . 34 | |||
2.4.1. Identifying the User by Reference . . . . . . . . . . 34 | 2.4.1. Identifying the User by Reference . . . . . . . . . . 35 | |||
2.5. Interacting with the User . . . . . . . . . . . . . . . . 35 | 2.5. Interacting with the User . . . . . . . . . . . . . . . . 35 | |||
2.5.1. Start Mode Definitions . . . . . . . . . . . . . . . 36 | 2.5.1. Start Mode Definitions . . . . . . . . . . . . . . . 37 | |||
2.5.2. Finish Interaction Modes . . . . . . . . . . . . . . 38 | 2.5.2. Finish Interaction Modes . . . . . . . . . . . . . . 38 | |||
2.5.3. Hints . . . . . . . . . . . . . . . . . . . . . . . . 40 | 2.5.3. Hints . . . . . . . . . . . . . . . . . . . . . . . . 41 | |||
2.5.4. Extending Interaction Modes . . . . . . . . . . . . . 41 | 2.5.4. Extending Interaction Modes . . . . . . . . . . . . . 41 | |||
2.6. Declaring Client Capabilities . . . . . . . . . . . . . . 41 | 2.6. Extending The Grant Request . . . . . . . . . . . . . . . 41 | |||
2.7. Referencing an Existing Grant Request . . . . . . . . . . 41 | ||||
2.8. Extending The Grant Request . . . . . . . . . . . . . . . 42 | ||||
3. Grant Response . . . . . . . . . . . . . . . . . . . . . . . 42 | 3. Grant Response . . . . . . . . . . . . . . . . . . . . . . . 42 | |||
3.1. Request Continuation . . . . . . . . . . . . . . . . . . 44 | 3.1. Request Continuation . . . . . . . . . . . . . . . . . . 43 | |||
3.2. Access Tokens . . . . . . . . . . . . . . . . . . . . . . 45 | 3.2. Access Tokens . . . . . . . . . . . . . . . . . . . . . . 44 | |||
3.2.1. Single Access Token . . . . . . . . . . . . . . . . . 45 | 3.2.1. Single Access Token . . . . . . . . . . . . . . . . . 45 | |||
3.2.2. Multiple Access Tokens . . . . . . . . . . . . . . . 48 | 3.2.2. Multiple Access Tokens . . . . . . . . . . . . . . . 48 | |||
3.3. Interaction Modes . . . . . . . . . . . . . . . . . . . . 50 | 3.3. Interaction Modes . . . . . . . . . . . . . . . . . . . . 49 | |||
3.3.1. Redirection to an arbitrary URL . . . . . . . . . . . 51 | 3.3.1. Redirection to an arbitrary URL . . . . . . . . . . . 50 | |||
3.3.2. Launch of an application URL . . . . . . . . . . . . 51 | 3.3.2. Launch of an application URL . . . . . . . . . . . . 51 | |||
3.3.3. Display of a Short User Code . . . . . . . . . . . . 52 | 3.3.3. Display of a Short User Code . . . . . . . . . . . . 51 | |||
3.3.4. Interaction Finish . . . . . . . . . . . . . . . . . 53 | 3.3.4. Interaction Finish . . . . . . . . . . . . . . . . . 52 | |||
3.3.5. Extending Interaction Mode Responses . . . . . . . . 54 | 3.3.5. Extending Interaction Mode Responses . . . . . . . . 53 | |||
3.4. Returning User Information . . . . . . . . . . . . . . . 54 | 3.4. Returning User Information . . . . . . . . . . . . . . . 53 | |||
3.5. Returning Dynamically-bound Reference Handles . . . . . . 55 | 3.5. Returning Dynamically-bound Reference Handles . . . . . . 54 | |||
3.6. Error Response . . . . . . . . . . . . . . . . . . . . . 56 | 3.6. Error Response . . . . . . . . . . . . . . . . . . . . . 56 | |||
3.7. Extending the Response . . . . . . . . . . . . . . . . . 57 | 3.7. Extending the Response . . . . . . . . . . . . . . . . . 56 | |||
4. Determining Authorization and Consent . . . . . . . . . . . . 57 | 4. Determining Authorization and Consent . . . . . . . . . . . . 56 | |||
4.1. Interaction Start Methods . . . . . . . . . . . . . . . . 60 | 4.1. Interaction Start Methods . . . . . . . . . . . . . . . . 59 | |||
4.1.1. Interaction at a Redirected URI . . . . . . . . . . . 61 | 4.1.1. Interaction at a Redirected URI . . . . . . . . . . . 60 | |||
4.1.2. Interaction at the User Code URI . . . . . . . . . . 61 | 4.1.2. Interaction at the User Code URI . . . . . . . . . . 60 | |||
4.1.3. Interaction through an Application URI . . . . . . . 62 | 4.1.3. Interaction through an Application URI . . . . . . . 61 | |||
4.2. Post-Interaction Completion . . . . . . . . . . . . . . . 62 | 4.2. Post-Interaction Completion . . . . . . . . . . . . . . . 61 | |||
4.2.1. Completing Interaction with a Browser Redirect to the | 4.2.1. Completing Interaction with a Browser Redirect to the | |||
Callback URI . . . . . . . . . . . . . . . . . . . . 63 | Callback URI . . . . . . . . . . . . . . . . . . . . 62 | |||
4.2.2. Completing Interaction with a Direct HTTP Request | 4.2.2. Completing Interaction with a Direct HTTP Request | |||
Callback . . . . . . . . . . . . . . . . . . . . . . 64 | Callback . . . . . . . . . . . . . . . . . . . . . . 63 | |||
4.2.3. Calculating the interaction hash . . . . . . . . . . 65 | 4.2.3. Calculating the interaction hash . . . . . . . . . . 64 | |||
5. Continuing a Grant Request . . . . . . . . . . . . . . . . . 66 | 5. Continuing a Grant Request . . . . . . . . . . . . . . . . . 65 | |||
5.1. Continuing After a Completed Interaction . . . . . . . . 68 | 5.1. Continuing After a Completed Interaction . . . . . . . . 67 | |||
5.2. Continuing During Pending Interaction . . . . . . . . . . 69 | 5.2. Continuing During Pending Interaction . . . . . . . . . . 68 | |||
5.3. Modifying an Existing Request . . . . . . . . . . . . . . 70 | 5.3. Modifying an Existing Request . . . . . . . . . . . . . . 69 | |||
5.4. Canceling a Grant Request . . . . . . . . . . . . . . . . 75 | 5.4. Canceling a Grant Request . . . . . . . . . . . . . . . . 75 | |||
6. Token Management . . . . . . . . . . . . . . . . . . . . . . 76 | 6. Token Management . . . . . . . . . . . . . . . . . . . . . . 75 | |||
6.1. Rotating the Access Token . . . . . . . . . . . . . . . . 76 | 6.1. Rotating the Access Token . . . . . . . . . . . . . . . . 75 | |||
6.2. Revoking the Access Token . . . . . . . . . . . . . . . . 78 | 6.2. Revoking the Access Token . . . . . . . . . . . . . . . . 77 | |||
7. Securing Requests from the Client Instance . . . . . . . . . 79 | 7. Securing Requests from the Client Instance . . . . . . . . . 78 | |||
7.1. Key Formats . . . . . . . . . . . . . . . . . . . . . . . 79 | 7.1. Key Formats . . . . . . . . . . . . . . . . . . . . . . . 78 | |||
7.1.1. Key References . . . . . . . . . . . . . . . . . . . 81 | 7.1.1. Key References . . . . . . . . . . . . . . . . . . . 80 | |||
7.2. Presenting Access Tokens . . . . . . . . . . . . . . . . 81 | 7.2. Presenting Access Tokens . . . . . . . . . . . . . . . . 80 | |||
7.3. Proving Possession of a Key with a Request . . . . . . . 82 | 7.3. Proving Possession of a Key with a Request . . . . . . . 81 | |||
7.3.1. Detached JWS . . . . . . . . . . . . . . . . . . . . 84 | 7.3.1. HTTP Message Signing . . . . . . . . . . . . . . . . 83 | |||
7.3.2. Attached JWS . . . . . . . . . . . . . . . . . . . . 88 | 7.3.2. Mutual TLS . . . . . . . . . . . . . . . . . . . . . 87 | |||
7.3.3. Mutual TLS . . . . . . . . . . . . . . . . . . . . . 92 | 7.3.3. Detached JWS . . . . . . . . . . . . . . . . . . . . 89 | |||
7.3.4. Demonstration of Proof-of-Possession (DPoP) . . . . . 94 | 7.3.4. Attached JWS . . . . . . . . . . . . . . . . . . . . 93 | |||
7.3.5. HTTP Message Signing . . . . . . . . . . . . . . . . 96 | 8. Resource Access Rights . . . . . . . . . . . . . . . . . . . 97 | |||
7.3.6. OAuth Proof of Possession (PoP) . . . . . . . . . . . 99 | 8.1. Requesting Resources By Reference . . . . . . . . . . . . 100 | |||
8. Resource Access Rights . . . . . . . . . . . . . . . . . . . 102 | 9. Discovery . . . . . . . . . . . . . . . . . . . . . . . . . . 102 | |||
8.1. Requesting Resources By Reference . . . . . . . . . . . . 106 | 9.1. RS-first Method of AS Discovery . . . . . . . . . . . . . 103 | |||
9. Discovery . . . . . . . . . . . . . . . . . . . . . . . . . . 108 | 10. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 105 | |||
10. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 109 | 11. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 105 | |||
11. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 110 | 12. Security Considerations . . . . . . . . . . . . . . . . . . . 105 | |||
12. Security Considerations . . . . . . . . . . . . . . . . . . . 110 | 13. Privacy Considerations . . . . . . . . . . . . . . . . . . . 105 | |||
13. Privacy Considerations . . . . . . . . . . . . . . . . . . . 110 | 14. Normative References . . . . . . . . . . . . . . . . . . . . 105 | |||
14. Normative References . . . . . . . . . . . . . . . . . . . . 110 | Appendix A. Document History . . . . . . . . . . . . . . . . . . 108 | |||
Appendix A. Document History . . . . . . . . . . . . . . . . . . 113 | Appendix B. Compared to OAuth 2.0 . . . . . . . . . . . . . . . 110 | |||
Appendix B. Compared to OAuth 2.0 . . . . . . . . . . . . . . . 115 | Appendix C. Component Data Models . . . . . . . . . . . . . . . 113 | |||
Appendix C. Component Data Models . . . . . . . . . . . . . . . 117 | Appendix D. Example Protocol Flows . . . . . . . . . . . . . . . 113 | |||
Appendix D. Example Protocol Flows . . . . . . . . . . . . . . . 117 | D.1. Redirect-Based User Interaction . . . . . . . . . . . . . 113 | |||
D.1. Redirect-Based User Interaction . . . . . . . . . . . . . 118 | D.2. Secondary Device Interaction . . . . . . . . . . . . . . 117 | |||
D.2. Secondary Device Interaction . . . . . . . . . . . . . . 122 | D.3. No User Involvement . . . . . . . . . . . . . . . . . . . 120 | |||
D.3. No User Involvement . . . . . . . . . . . . . . . . . . . 125 | D.4. Asynchronous Authorization . . . . . . . . . . . . . . . 121 | |||
D.4. Asynchronous Authorization . . . . . . . . . . . . . . . 126 | D.5. Applying OAuth 2.0 Scopes and Client IDs . . . . . . . . 124 | |||
D.5. Applying OAuth 2.0 Scopes and Client IDs . . . . . . . . 129 | Appendix E. JSON Structures and Polymorphism . . . . . . . . . . 126 | |||
Appendix E. JSON Structures and Polymorphism . . . . . . . . . . 131 | Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 127 | |||
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 132 | ||||
1. Introduction | 1. Introduction | |||
This protocol allows a piece of software, the client instance, to | This protocol allows a piece of software, the client instance, to | |||
request delegated authorization to resource servers and to request | request delegated authorization to resource servers and to request | |||
direct information. This delegation is facilitated by an | direct information. This delegation is facilitated by an | |||
authorization server usually on behalf of a resource owner. The end- | authorization server usually on behalf of a resource owner. The end- | |||
user operating the software may interact with the authorization | user operating the software may interact with the authorization | |||
server to authenticate, provide consent, and authorize the request. | server to authenticate, provide consent, and authorize the request. | |||
The process by which the delegation happens is known as a grant, and | The process by which the delegation happens is known as a grant, and | |||
GNAP allows for the negotiation of the grant process over time by | GNAP allows for the negotiation of the grant process over time by | |||
multiple parties acting in distinct roles. | multiple parties acting in distinct roles. | |||
This specification focuses on the portions of the delegation process | ||||
facing the client instance. In particular, this specification | ||||
defines interoperable methods for a client instance to request, | ||||
negotiate, and receive access to information facilitated by the | ||||
authorization server. This specification also discusses discovery | ||||
mechanisms for the client instance to configure itself dynamically. | ||||
The means for an authorization server and resource server to | ||||
interoperate are discussed in the companion document, | ||||
[I-D.draft-ietf-gnap-resource-servers]. | ||||
The focus of this protocol is to provide interoperability between the | The focus of this protocol is to provide interoperability between the | |||
different parties acting in each role, and is not to specify | different parties acting in each role, and is not to specify | |||
implementation details of each. Where appropriate, GNAP may make | implementation details of each. Where appropriate, GNAP may make | |||
recommendations about internal implementation details, but these | recommendations about internal implementation details, but these | |||
recommendations are to ensure the security of the overall deployment | recommendations are to ensure the security of the overall deployment | |||
rather than to be prescriptive in the implementation. | rather than to be prescriptive in the implementation. | |||
This protocol solves many of the same use cases as OAuth 2.0 | This protocol solves many of the same use cases as OAuth 2.0 | |||
[RFC6749], OpenID Connect [OIDC], and the family of protocols that | [RFC6749], OpenID Connect [OIDC], and the family of protocols that | |||
have grown up around that ecosystem. However, GNAP is not an | have grown up around that ecosystem. However, GNAP is not an | |||
skipping to change at page 5, line 26 ¶ | skipping to change at page 6, line 5 ¶ | |||
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. | |||
1.2. Roles | 1.2. Roles | |||
The parties in GNAP perform actions under different roles. Roles are | The parties in GNAP perform actions under different roles. Roles are | |||
defined by the actions taken and the expectations leveraged on the | defined by the actions taken and the expectations leveraged on the | |||
role by the overall protocol. | role by the overall protocol. | |||
+-------------+ +------------+ | ||||
| | | | | ||||
|Authorization| | Resource | | ||||
| Server | | Server | | ||||
| |<-+ +---->| | | ||||
+-------------+ | | +------------+ | ||||
+ | | | ||||
+ | | | ||||
+ | | | ||||
+ | | | ||||
+ | | | ||||
+ +----------+ | ||||
+ | Client | | ||||
+ | Instance | | ||||
+ +----------+ | ||||
+ + | ||||
+ + | ||||
+ + | ||||
+-----------+ + +------------+ | ||||
| | + + + +| | | ||||
| Resource | | End | | ||||
| Owner | ~ ~ ~ ~ ~ ~ | User | | ||||
| | | | | ||||
+-----------+ +------------+ | ||||
Legend | ||||
+ + + indicates interaction between a human and computer | ||||
----- indicates interaction between two pieces of software | ||||
~ ~ ~ indicates a potential equivalence or out-of-band communication between roles | ||||
Authorization Server (AS) server that grants delegated privileges to | Authorization Server (AS) server that grants delegated privileges to | |||
a particular instance of client software in the form of access | a particular instance of client software in the form of access | |||
tokens or other information (such as subject information). | tokens or other information (such as subject information). | |||
Client application operated by an end-user that consumes resources | Client application operated by an end-user that consumes resources | |||
from one or several RSs, possibly requiring access privileges from | from one or several RSs, possibly requiring access privileges from | |||
one or several ASs. | one or several ASs. | |||
Example: a client can be a mobile application, a web application, | Example: a client can be a mobile application, a web application, | |||
etc. | etc. | |||
skipping to change at page 9, line 5 ¶ | skipping to change at page 10, line 5 ¶ | |||
In some circumstances, the information needed at a given stage is | In some circumstances, the information needed at a given stage is | |||
communicated out of band or is preconfigured between the components | communicated out of band or is preconfigured between the components | |||
or entities performing the roles. For example, one entity can fulfil | or entities performing the roles. For example, one entity can fulfil | |||
multiple roles, and so explicit communication between the roles is | multiple roles, and so explicit communication between the roles is | |||
not necessary within the protocol flow. Additionally some components | not necessary within the protocol flow. Additionally some components | |||
may not be involved in all use cases. For example, a client instance | may not be involved in all use cases. For example, a client instance | |||
could be calling the AS just to get direct user information and have | could be calling the AS just to get direct user information and have | |||
no need to get an access token to call an RS. | no need to get an access token to call an RS. | |||
+------------+ +------------+ | +------------+ +------------+ | |||
| End-user | ~ ~ ~ ~ | Resource | | | End-user | ~ ~ ~ ~ | Resource | | |||
| | | Owner (RO) | | | | | Owner (RO) | | |||
+------------+ +------------+ | +------------+ +------------+ | |||
+ + | + + | |||
+ + | + + | |||
(A) (B) | (A) (B) | |||
+ + | + + | |||
+ + | + + | |||
+--------+ + +------------+ | +--------+ + +------------+ | |||
| Client | (1) + | Resource | | | Client | (1) + | Resource | | |||
|Instance| + | Server | | |Instance| + | Server | | |||
| | +---------------+ | (RS) | | | | +---------------+ | (RS) | | |||
| |--(2)->| Authorization | | | | | |--(2)->| Authorization | | | | |||
| |<-(3)--| Server | | | | | |<-(3)--| Server | | | | |||
| | | (AS) | | | | | | | (AS) | | | | |||
| |--(4)->| | | | | | |--(4)->| | | | | |||
| |<-(5)--| | | | | | |<-(5)--| | | | | |||
| |--------------(6)------------->| | | | |--------------(6)------------->| | | |||
| | | | (7) | | | | | | | (7) | | | |||
| |<-------------(8)------------->| | | | |<-------------(8)------------->| | | |||
| |--(9)->| | | | | | |--(9)->| | | | | |||
| |<-(10)-| | | | | | |<-(10)-| | | | | |||
| |--------------(11)------------>| | | | |--------------(11)------------>| | | |||
| | | | (12) | | | | | | | (12) | | | |||
| |-(13)->| | | | | | |-(13)->| | | | | |||
| | | | | | | | | | | | | | |||
+--------+ +---------------+ +------------+ | +--------+ +---------------+ +------------+ | |||
Legend | Legend | |||
+ + + indicates a possible interaction with a human | + + + indicates a possible interaction with a human | |||
----- indicates an interaction between protocol roles | ----- indicates an interaction between protocol roles | |||
~ ~ ~ indicates a potential equivalence or out-of-band | ~ ~ ~ indicates a potential equivalence or out-of-band | |||
communication between roles | communication between roles | |||
* (A) The end-user interacts with the client instance to indicate a | * (A) The end-user interacts with the client instance to indicate a | |||
need for resources on behalf of the RO. This could identify the | need for resources on behalf of the RO. This could identify the | |||
RS the client instance needs to call, the resources needed, or the | RS the client instance needs to call, the resources needed, or the | |||
RO that is needed to approve the request. Note that the RO and | RO that is needed to approve the request. Note that the RO and | |||
end-user are often the same entity in practice, but some more | end-user are often the same entity in practice, but some more | |||
dynamic processes are discussed in | dynamic processes are discussed in | |||
[I-D.draft-ietf-gnap-resource-servers]. | [I-D.draft-ietf-gnap-resource-servers]. | |||
* (1) The client instance determines what access is needed and which | * (1) The client instance determines what access is needed and which | |||
skipping to change at page 23, line 8 ¶ | skipping to change at page 24, line 8 ¶ | |||
user (object / string) Identifies the end-user to the AS in a manner | user (object / string) Identifies the end-user to the AS in a manner | |||
that the AS can verify, either directly or by interacting with the | that the AS can verify, either directly or by interacting with the | |||
end-user to determine their status as the RO. Section 2.4 | end-user to determine their status as the RO. Section 2.4 | |||
interact (object) Describes the modes that the client instance has | interact (object) Describes the modes that the client instance has | |||
for allowing the RO to interact with the AS and modes for the | for allowing the RO to interact with the AS and modes for the | |||
client instance to receive updates when interaction is complete. | client instance to receive updates when interaction is complete. | |||
Section 2.5 | Section 2.5 | |||
capabilities (array of strings) Identifies named extension | ||||
capabilities that the client instance can use, signaling to the AS | ||||
which extensions it can use. Section 2.6 | ||||
existing_grant (string) Identifies a previously-existing grant that | ||||
the client instance is extending with this request. Section 2.7 | ||||
Additional members of this request object can be defined by | Additional members of this request object can be defined by | |||
extensions to this protocol as described in Section 2.8 | extensions to this protocol as described in Section 2.6 | |||
A non-normative example of a grant request is below: | A non-normative example of a grant request is below: | |||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
{ | { | |||
"type": "photo-api", | "type": "photo-api", | |||
"actions": [ | "actions": [ | |||
"read", | "read", | |||
skipping to change at page 23, line 48 ¶ | skipping to change at page 24, line 41 ¶ | |||
}, | }, | |||
"dolphin-metadata" | "dolphin-metadata" | |||
] | ] | |||
}, | }, | |||
"client": { | "client": { | |||
"display": { | "display": { | |||
"name": "My Client Display Name", | "name": "My Client Display Name", | |||
"uri": "https://example.net/client" | "uri": "https://example.net/client" | |||
}, | }, | |||
"key": { | "key": { | |||
"proof": "jwsd", | "proof": "httpsig", | |||
"jwk": { | "jwk": { | |||
"kty": "RSA", | "kty": "RSA", | |||
"e": "AQAB", | "e": "AQAB", | |||
"kid": "xyz-1", | "kid": "xyz-1", | |||
"alg": "RS256", | "alg": "RS256", | |||
"n": "kOB5rR4Jv0GMeL...." | "n": "kOB5rR4Jv0GMeL...." | |||
} | } | |||
} | } | |||
}, | }, | |||
"interact": { | "interact": { | |||
"start": ["redirect"], | "start": ["redirect"], | |||
"finish": { | "finish": { | |||
"method": "redirect", | "method": "redirect", | |||
"uri": "https://client.example.net/return/123455", | "uri": "https://client.example.net/return/123455", | |||
"nonce": "LKLTI25DK82FX4T4QFZC" | "nonce": "LKLTI25DK82FX4T4QFZC" | |||
} | } | |||
}, | }, | |||
"capabilities": ["ext1", "ext2"], | ||||
"subject": { | "subject": { | |||
"formats": ["iss_sub", "opaque"], | "formats": ["iss_sub", "opaque"], | |||
"assertions": ["id_token"] | "assertions": ["id_token"] | |||
} | } | |||
} | } | |||
The request and response MUST be sent as a JSON object in the body of | The request and response MUST be sent as a JSON object in the body of | |||
the HTTP POST request with Content-Type "application/json", unless | the HTTP POST request with Content-Type "application/json", unless | |||
otherwise specified by the signature mechanism. | otherwise specified by the signature mechanism. | |||
skipping to change at page 25, line 17 ¶ | skipping to change at page 26, line 8 ¶ | |||
field is REQUIRED if used as part of a multiple access token | field is REQUIRED if used as part of a multiple access token | |||
request (Section 2.1.2), and is OPTIONAL otherwise. | request (Section 2.1.2), and is OPTIONAL otherwise. | |||
flags (array of strings) A set of flags that indicate desired | flags (array of strings) A set of flags that indicate desired | |||
attributes or behavior to be attached to the access token by the | attributes or behavior to be attached to the access token by the | |||
AS. This field is OPTIONAL. | AS. This field is OPTIONAL. | |||
The values of the "flags" field defined by this specification are as | The values of the "flags" field defined by this specification are as | |||
follows: | follows: | |||
bearer If this flag is included, the access token being requested is | "bearer" If this flag is included, the access token being requested | |||
a bearer token. If this flag is omitted, the access token is | is a bearer token. If this flag is omitted, the access token is | |||
bound to the key used by the client instance in this request, or | bound to the key used by the client instance in this request, or | |||
the key's most recent rotation. Methods for presenting bound and | the key's most recent rotation. Methods for presenting bound and | |||
bearer access tokens are described in Section 7.2. [[ See issue | bearer access tokens are described in Section 7.2. [[ See issue | |||
#38 (https://github.com/ietf-wg-gnap/gnap-core-protocol/issues/38) | #38 (https://github.com/ietf-wg-gnap/gnap-core-protocol/issues/38) | |||
]] | ]] | |||
split If this flag is included, the client instance is capable of | "split" If this flag is included, the client instance is capable of | |||
receiving a different number of tokens than specified in the token | receiving a different number of tokens than specified in the token | |||
request (Section 2.1), including receiving multiple access tokens | request (Section 2.1), including receiving multiple access tokens | |||
(Section 3.2.2) in response to any single token request | (Section 3.2.2) in response to any single token request | |||
(Section 2.1.1) or a different number of access tokens than | (Section 2.1.1) or a different number of access tokens than | |||
requested in a multiple access token request (Section 2.1.2). The | requested in a multiple access token request (Section 2.1.2). The | |||
"label" fields of the returned additional tokens are chosen by the | "label" fields of the returned additional tokens are chosen by the | |||
AS. The client instance MUST be able to tell from the token | AS. The client instance MUST be able to tell from the token | |||
response where and how it can use each of the access tokens. [[ | response where and how it can use each of the access tokens. [[ | |||
See issue #37 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | See issue #37 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | |||
issues/37) ]] | issues/37) ]] | |||
skipping to change at page 31, line 28 ¶ | skipping to change at page 32, line 28 ¶ | |||
AS policy, attestations within the "client" request, and other | AS policy, attestations within the "client" request, and other | |||
mechanisms. | mechanisms. | |||
[[ See issue #44 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | [[ See issue #44 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | |||
issues/44) ]] | issues/44) ]] | |||
2.3.1. Identifying the Client Instance by Reference | 2.3.1. Identifying the Client Instance by Reference | |||
If the client instance has an instance identifier that the AS can use | If the client instance has an instance identifier that the AS can use | |||
to determine appropriate key information, the client instance can | to determine appropriate key information, the client instance can | |||
send this value in the "instance_id" field. The instance identifier | send this instance identifier as a direct reference value in lieu of | |||
MAY be assigned to a client instance at runtime through the | the "client" object. The instance identifier MAY be assigned to a | |||
Section 3.5 or MAY be obtained in another fashion, such as a static | client instance at runtime through the Section 3.5 or MAY be obtained | |||
registration process at the AS. | in another fashion, such as a static registration process at the AS. | |||
instance_id (string) An identifier string that the AS can use to | ||||
identify the particular instance of this client software. The | ||||
content and structure of this identifier is opaque to the client | ||||
instance. | ||||
"client": { | ||||
"instance_id": "client-541-ab" | ||||
} | ||||
If there are no additional fields to send, the client instance MAY | ||||
send the instance identifier as a direct reference value in lieu of | ||||
the object. | ||||
"client": "client-541-ab" | "client": "client-541-ab" | |||
When the AS receives a request with an instance identifier, the AS | When the AS receives a request with an instance identifier, the AS | |||
MUST ensure that the key used to sign the request (Section 7.3) is | MUST ensure that the key used to sign the request (Section 7.3) is | |||
associated with the instance identifier. | associated with the instance identifier. | |||
If the "instance_id" field is sent, it MUST NOT be accompanied by | ||||
other fields unless such fields are explicitly marked safe for | ||||
inclusion alongside the instance identifier. | ||||
[[ See issue #45 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | ||||
issues/45) ]] | ||||
If the AS does not recognize the instance identifier, the request | If the AS does not recognize the instance identifier, the request | |||
MUST be rejected with an error. | MUST be rejected with an error. | |||
If the client instance is identified in this manner, the registered | If the client instance is identified in this manner, the registered | |||
key for the client instance MAY be a symmetric key known to the AS. | key for the client instance MAY be a symmetric key known to the AS. | |||
The client instance MUST NOT send a symmetric key by value in the | The client instance MUST NOT send a symmetric key by value in the | |||
request, as doing so would expose the key directly instead of proving | request, as doing so would expose the key directly instead of proving | |||
possession of it. | possession of it. | |||
2.3.2. Providing Displayable Client Instance Information | 2.3.2. Providing Displayable Client Instance Information | |||
skipping to change at page 41, line 28 ¶ | skipping to change at page 41, line 45 ¶ | |||
If possible, the AS SHOULD use one of the locales in the array, with | If possible, the AS SHOULD use one of the locales in the array, with | |||
preference to the first item in the array supported by the AS. If | preference to the first item in the array supported by the AS. If | |||
none of the given locales are supported, the AS MAY use a default | none of the given locales are supported, the AS MAY use a default | |||
locale. | locale. | |||
2.5.4. Extending Interaction Modes | 2.5.4. Extending Interaction Modes | |||
Additional interaction start modes, finish modes, and hints are | Additional interaction start modes, finish modes, and hints are | |||
defined in a registry TBD (Section 11). | defined in a registry TBD (Section 11). | |||
2.6. Declaring Client Capabilities | 2.6. Extending The Grant Request | |||
If the client software supports extension capabilities, the client | ||||
instance MAY present them to the AS in the "capabilities" field. | ||||
This field is an array of strings representing specific extensions | ||||
and capabilities, as defined by a registry TBD (Section 11). | ||||
"capabilities": ["ext1", "ext2"] | ||||
2.7. Referencing an Existing Grant Request | ||||
If the client instance has a reference handle from a previously | ||||
granted request, it MAY send that reference in the "existing_grant" | ||||
field. This field is a single string consisting of the "value" of | ||||
the "access_token" returned in a previous request's continuation | ||||
response (Section 3.1). | ||||
"existing_grant": "80UPRY5NM33OMUKMKSKU" | ||||
The AS MUST dereference the grant associated with the reference and | ||||
process this request in the context of the referenced one. The AS | ||||
MUST NOT alter the existing grant associated with the reference. | ||||
[[ See issue #62 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | ||||
issues/62) ]] | ||||
2.8. Extending The Grant Request | ||||
The request object MAY be extended by registering new items in a | The request object MAY be extended by registering new items in a | |||
registry TBD (Section 11). Extensions SHOULD be orthogonal to other | registry TBD (Section 11). Extensions SHOULD be orthogonal to other | |||
parameters. Extensions MUST document any aspects where the extension | parameters. Extensions MUST document any aspects where the extension | |||
item affects or influences the values or behavior of other request | item affects or influences the values or behavior of other request | |||
and response objects. | and response objects. | |||
3. Grant Response | 3. Grant Response | |||
In response to a client instance's request, the AS responds with a | In response to a client instance's request, the AS responds with a | |||
skipping to change at page 43, line 14 ¶ | skipping to change at page 42, line 48 ¶ | |||
{ | { | |||
"interact": { | "interact": { | |||
"redirect": "https://server.example.com/interact/4CF492ML\ | "redirect": "https://server.example.com/interact/4CF492ML\ | |||
VMSW9MKMXKHQ", | VMSW9MKMXKHQ", | |||
"finish": "MBDOFXG4Y5CVJCX821LH" | "finish": "MBDOFXG4Y5CVJCX821LH" | |||
}, | }, | |||
"continue": { | "continue": { | |||
"access_token": { | "access_token": { | |||
"value": "80UPRY5NM33OMUKMKSKU", | "value": "80UPRY5NM33OMUKMKSKU", | |||
"bound": true | ||||
}, | }, | |||
"uri": "https://server.example.com/tx" | "uri": "https://server.example.com/tx" | |||
} | } | |||
} | } | |||
In this example, the AS is returning a bearer access token | In this example, the AS is returning a bearer access token | |||
(Section 3.2.1) with a management URL and a subject identifier | (Section 3.2.1) with a management URL and a subject identifier | |||
(Section 3.4) in the form of an opaque identifier. | (Section 3.4) in the form of an opaque identifier. | |||
{ | { | |||
"access_token": { | "access_token": { | |||
"value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0", | "value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0", | |||
"bound": false, | "flags": ["bearer"], | |||
"manage": "https://server.example.com/token/PRY5NM33O\ | "manage": "https://server.example.com/token/PRY5NM33O\ | |||
M4TB8N6BW7OZB8CDFONP219RP1L", | M4TB8N6BW7OZB8CDFONP219RP1L", | |||
}, | }, | |||
"subject": { | "subject": { | |||
"sub_ids": [ { | "sub_ids": [ { | |||
"format": "opaque", | "format": "opaque", | |||
"id": "J2G8G8O4AZ" | "id": "J2G8G8O4AZ" | |||
} ] | } ] | |||
} | } | |||
} | } | |||
In this example, the AS is returning only a pair of subject | In this example, the AS is returning set of subject identifiers | |||
identifiers (Section 3.4) as both an email address and an opaque | (Section 3.4), simultaneously as an opaque identifier, an email | |||
identifier. | address, and a decentralized identifier (DID). | |||
{ | { | |||
"subject": { | "subject": { | |||
"sub_ids": [ { | "sub_ids": [ { | |||
"subject_type": "opaque", | "subject_type": "opaque", | |||
"id": "J2G8G8O4AZ" | "id": "J2G8G8O4AZ" | |||
}, { | }, { | |||
"format": "email", | "format": "email", | |||
"email": "user@example.com" | "email": "user@example.com" | |||
}, { | ||||
"format": "did", | ||||
"url": "did:example:123456" | ||||
} ] | } ] | |||
} | } | |||
} | } | |||
3.1. Request Continuation | 3.1. Request Continuation | |||
If the AS determines that the request can be continued with | If the AS determines that the request can be continued with | |||
additional requests, it responds with the "continue" field. This | additional requests, it responds with the "continue" field. This | |||
field contains a JSON object with the following properties. | field contains a JSON object with the following properties. | |||
skipping to change at page 44, line 37 ¶ | skipping to change at page 44, line 17 ¶ | |||
continuation request (Section 5). | continuation request (Section 5). | |||
wait (integer) RECOMMENDED. The amount of time in integer seconds | wait (integer) RECOMMENDED. The amount of time in integer seconds | |||
the client instance SHOULD wait after receiving this continuation | the client instance SHOULD wait after receiving this continuation | |||
handle and calling the URI. | handle and calling the URI. | |||
access_token (object) REQUIRED. A unique access token for | access_token (object) REQUIRED. A unique access token for | |||
continuing the request, in the format specified in Section 3.2.1. | continuing the request, in the format specified in Section 3.2.1. | |||
This access token MUST be bound to the client instance's key used | This access token MUST be bound to the client instance's key used | |||
in the request and MUST NOT be a "bearer" token. As a | in the request and MUST NOT be a "bearer" token. As a | |||
consequence, the "bound" field of this access token is always the | consequence, the "flags" array of this access token MUST NOT | |||
boolean value "true" and the "key" field MUST be omitted. This | contain the string "bearer" and the "key" field MUST be omitted. | |||
access token MUST NOT be usable at resources outside of the AS. | This access token MUST NOT be usable at resources outside of the | |||
The client instance MUST present the access token in all requests | AS. The client instance MUST present the access token in all | |||
to the continuation URI as described in Section 7.2. [[ See issue | requests to the continuation URI as described in Section 7.2. [[ | |||
#66 (https://github.com/ietf-wg-gnap/gnap-core-protocol/issues/66) | See issue #66 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | |||
]] | issues/66) ]] | |||
{ | { | |||
"continue": { | "continue": { | |||
"access_token": { | "access_token": { | |||
"value": "80UPRY5NM33OMUKMKSKU" | "value": "80UPRY5NM33OMUKMKSKU" | |||
}, | }, | |||
"uri": "https://server.example.com/continue", | "uri": "https://server.example.com/continue", | |||
"wait": 60 | "wait": 60 | |||
} | } | |||
} | } | |||
skipping to change at page 45, line 49 ¶ | skipping to change at page 45, line 21 ¶ | |||
has granted that access token, the AS responds with the | has granted that access token, the AS responds with the | |||
"access_token" field. The value of this field is an object with the | "access_token" field. The value of this field is an object with the | |||
following properties. | following properties. | |||
value (string) REQUIRED. The value of the access token as a string. | value (string) REQUIRED. The value of the access token as a string. | |||
The value is opaque to the client instance. The value SHOULD be | The value is opaque to the client instance. The value SHOULD be | |||
limited to ASCII characters to facilitate transmission over HTTP | limited to ASCII characters to facilitate transmission over HTTP | |||
headers within other protocols without requiring additional | headers within other protocols without requiring additional | |||
encoding. | encoding. | |||
bound (boolean) RECOMMENDED. Flag indicating if the token is bound | ||||
to the client instance's key. If the boolean value is "true" or | ||||
the field is omitted, and the "key" field is omitted, the token is | ||||
bound to the key used by the client instance (Section 2.3) in its | ||||
request for access. If the boolean value is "true" or the field | ||||
is omitted, and the "key" field is present, the token is bound to | ||||
the key and proofing mechanism indicated in the "key" field. If | ||||
the boolean value is "false", the token is a bearer token with no | ||||
key bound to it and the "key" field MUST be omitted. | ||||
label (string) REQUIRED for multiple access tokens, OPTIONAL for | label (string) REQUIRED for multiple access tokens, OPTIONAL for | |||
single access token. The value of the "label" the client instance | single access token. The value of the "label" the client instance | |||
provided in the associated token request (Section 2.1), if | provided in the associated token request (Section 2.1), if | |||
present. If the token has been split by the AS, the value of the | present. If the token has been split by the AS, the value of the | |||
"label" field is chosen by the AS and the "split" field is | "label" field is chosen by the AS and the "split" field is | |||
included and set to "true". | included and set to "true". | |||
manage (string) OPTIONAL. The management URI for this access token. | manage (string) OPTIONAL. The management URI for this access token. | |||
If provided, the client instance MAY manage its access token as | If provided, the client instance MAY manage its access token as | |||
described in Section 6. This management URI is a function of the | described in Section 6. This management URI is a function of the | |||
skipping to change at page 46, line 42 ¶ | skipping to change at page 46, line 5 ¶ | |||
token past this time. An RS MUST NOT accept an access token past | token past this time. An RS MUST NOT accept an access token past | |||
this time. Note that the access token MAY be revoked by the AS or | this time. Note that the access token MAY be revoked by the AS or | |||
RS at any point prior to its expiration. | RS at any point prior to its expiration. | |||
key (object / string) OPTIONAL. The key that the token is bound to, | key (object / string) OPTIONAL. The key that the token is bound to, | |||
if different from the client instance's presented key. The key | if different from the client instance's presented key. The key | |||
MUST be an object or string in a format described in Section 7.1. | MUST be an object or string in a format described in Section 7.1. | |||
The client instance MUST be able to dereference or process the key | The client instance MUST be able to dereference or process the key | |||
information in order to be able to sign the request. | information in order to be able to sign the request. | |||
durable (boolean) OPTIONAL. Flag indicating a hint of AS behavior | flags (array of strings) OPTIONAL. A set of flags that represent | |||
on token rotation. If this flag is set to the value "true", then | attributes or behaviors of the access token issued by the AS. | |||
the client instance can expect a previously-issued access token to | ||||
continue to work after it has been rotated (Section 6.1) or the | ||||
underlying grant request has been modified (Section 5.3), | ||||
resulting in the issuance of new access tokens. If this flag is | ||||
set to the boolean value "false" or is omitted, the client | ||||
instance can anticipate a given access token will stop working | ||||
after token rotation or grant request modification. Note that a | ||||
token flagged as "durable" can still expire or be revoked through | ||||
any normal means. | ||||
split (boolean) OPTIONAL. Flag indicating that this token was | The values of the "flags" field defined by this specification are as | |||
generated by issuing multiple access tokens in response to one of | follows: | |||
the client instance's token request (Section 2.1) objects. This | ||||
behavior MUST NOT be used unless the client instance has | "bearer" This flag indicates whether the token is bound to the | |||
specifically requested it by use of the "split" flag. | client instance's key. If the "bearer" flag is present, the | |||
access token is a bearer token, and the "key" field in this | ||||
response MUST be omitted. If the "bearer" flag is omitted and the | ||||
"key" field in this response is omitted, the token is bound the | ||||
key used by the client instance (Section 2.3) in its request for | ||||
access. If the "bearer" flag is omitted, and the "key" field is | ||||
present, the token is bound to the key and proofing mechanism | ||||
indicated in the "key" field. | ||||
"durable" OPTIONAL. Flag indicating a hint of AS behavior on token | ||||
rotation. If this flag is present, then the client instance can | ||||
expect a previously-issued access token to continue to work after | ||||
it has been rotated (Section 6.1) or the underlying grant request | ||||
has been modified (Section 5.3), resulting in the issuance of new | ||||
access tokens. If this flag is omitted, the client instance can | ||||
anticipate a given access token will stop working after token | ||||
rotation or grant request modification. Note that a token flagged | ||||
as "durable" can still expire or be revoked through any normal | ||||
means. | ||||
"split" OPTIONAL. Flag indicating that this token was generated by | ||||
issuing multiple access tokens in response to one of the client | ||||
instance's token request (Section 2.1) objects. This behavior | ||||
MUST NOT be used unless the client instance has specifically | ||||
requested it by use of the "split" flag. | ||||
Flag values MUST NOT be included more than once. | ||||
Additional flags can be defined by extensions using a registry TBD | ||||
(Section 11). | ||||
The following non-normative example shows a single access token bound | The following non-normative example shows a single access token bound | |||
to the client instance's key used in the initial request, with a | to the client instance's key used in the initial request, with a | |||
management URL, and that has access to three described resources (one | management URL, and that has access to three described resources (one | |||
using an object and two described by reference strings). | using an object and two described by reference strings). | |||
"access_token": { | "access_token": { | |||
"value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0", | "value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0", | |||
"manage": "https://server.example.com/token/PRY5NM33O\ | "manage": "https://server.example.com/token/PRY5NM33O\ | |||
M4TB8N6BW7OZB8CDFONP219RP1L", | M4TB8N6BW7OZB8CDFONP219RP1L", | |||
skipping to change at page 48, line 4 ¶ | skipping to change at page 47, line 29 ¶ | |||
"https://resource.local/other" | "https://resource.local/other" | |||
], | ], | |||
"datatypes": [ | "datatypes": [ | |||
"metadata", | "metadata", | |||
"images" | "images" | |||
] | ] | |||
}, | }, | |||
"read", "dolphin-metadata" | "read", "dolphin-metadata" | |||
] | ] | |||
} | } | |||
The following non-normative example shows a single bearer access | The following non-normative example shows a single bearer access | |||
token with access to two described resources. | token with access to two described resources. | |||
"access_token": { | "access_token": { | |||
"value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0", | "value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0", | |||
"bound": false, | "flags": ["bearer"], | |||
"access": [ | "access": [ | |||
"finance", "medical" | "finance", "medical" | |||
] | ] | |||
} | } | |||
If the client instance requested a single access token | If the client instance requested a single access token | |||
(Section 2.1.1), the AS MUST NOT respond with the multiple access | (Section 2.1.1), the AS MUST NOT respond with the multiple access | |||
token structure unless the client instance sends the "split" flag as | token structure unless the client instance sends the "split" flag as | |||
described in Section 2.1.1. | described in Section 2.1.1. | |||
If the AS has split the access token response, the response MUST | If the AS has split the access token response, the response MUST | |||
include the "split" flag set to "true". | include the "split" flag. | |||
[[ See issue #69 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | [[ See issue #69 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | |||
issues/69) ]] | issues/69) ]] | |||
3.2.2. Multiple Access Tokens | 3.2.2. Multiple Access Tokens | |||
If the client instance has requested multiple access tokens and the | If the client instance has requested multiple access tokens and the | |||
AS has granted at least one of them, the AS responds with the | AS has granted at least one of them, the AS responds with the | |||
"access_token" field. The value of this field is a JSON array, the | "access_token" field. The value of this field is a JSON array, the | |||
members of which are distinct access tokens as described in | members of which are distinct access tokens as described in | |||
skipping to change at page 49, line 39 ¶ | skipping to change at page 49, line 6 ¶ | |||
tokens are included in the response the requested names appropriate | tokens are included in the response the requested names appropriate | |||
names. | names. | |||
If the client instance requested multiple access tokens | If the client instance requested multiple access tokens | |||
(Section 2.1.2), the AS MUST NOT respond with a single access token | (Section 2.1.2), the AS MUST NOT respond with a single access token | |||
structure, even if only a single access token is granted. In such | structure, even if only a single access token is granted. In such | |||
cases, the AS responds with a multiple access token structure | cases, the AS responds with a multiple access token structure | |||
containing one access token. | containing one access token. | |||
If the AS has split the access token response, the response MUST | If the AS has split the access token response, the response MUST | |||
include the "split" flag set to "true". | include the "split" flag in the "flags" array. | |||
"access_token": [ | "access_token": [ | |||
{ | { | |||
"label": "split-1", | "label": "split-1", | |||
"value": "8N6BW7OZB8CDFONP219-OS9M2PMHKUR64TBRP1LT0", | "value": "8N6BW7OZB8CDFONP219-OS9M2PMHKUR64TBRP1LT0", | |||
"split": true, | "flags": ["split"], | |||
"manage": "https://server.example.com/token/PRY5NM33O\ | "manage": "https://server.example.com/token/PRY5NM33O\ | |||
M4TB8N6BW7OZB8CDFONP219RP1L", | M4TB8N6BW7OZB8CDFONP219RP1L", | |||
"access": [ "fruits" ] | "access": [ "fruits" ] | |||
}, | }, | |||
{ | { | |||
"label": "split-2", | "label": "split-2", | |||
"value": "FG7VGZZPJ3IZEMN21EVU71FHCAR-UFGLO2FDAP4J1", | "value": "FG7VGZZPJ3IZEMN21EVU71FHCAR-UFGLO2FDAP4J1", | |||
"split": true, | "flags": ["split"], | |||
"access": [ "vegetables" ] | "access": [ "vegetables" ] | |||
} | } | |||
} | } | |||
Each access token MAY be bound to different keys with different | Each access token MAY be bound to different keys with different | |||
proofing mechanisms. | proofing mechanisms. | |||
If token management (Section 6) is allowed, each access token SHOULD | If token management (Section 6) is allowed, each access token SHOULD | |||
have different "manage" URIs. | have different "manage" URIs. | |||
skipping to change at page 65, line 15 ¶ | skipping to change at page 64, line 15 ¶ | |||
4.2.3. Calculating the interaction hash | 4.2.3. Calculating the interaction hash | |||
The "hash" parameter in the request to the client instance's callback | The "hash" parameter in the request to the client instance's callback | |||
URL ties the front channel response to an ongoing request by using | URL ties the front channel response to an ongoing request by using | |||
values known only to the parties involved. This security mechanism | values known only to the parties involved. This security mechanism | |||
allows the client instance to protect itself against several kinds of | allows the client instance to protect itself against several kinds of | |||
session fixation and injection attacks. The AS MUST always provide | session fixation and injection attacks. The AS MUST always provide | |||
this hash, and the client instance MUST validate the hash when | this hash, and the client instance MUST validate the hash when | |||
received. | received. | |||
To calculate the "hash" value, the party doing the calculation first | To calculate the "hash" value, the party doing the calculation | |||
takes the "nonce" value sent by the client instance in the | creates a hash string by concatenating the following values in the | |||
interaction section of the initial request (Section 2.5.2), the AS's | following order using a single newline ("\\n") character to separate | |||
nonce value from the interaction finish response (Section 3.3.4), and | them: | |||
the "interact_ref" sent to the client instance's callback URL. These | ||||
three values are concatenated to each other in this order using a | * the "nonce" value sent by the client instance in the interaction | |||
single newline character as a separator between the fields. There is | "finish" section of the initial request (Section 2.5.2) | |||
no padding or whitespace before or after any of the lines, and no | ||||
trailing newline character. | * the AS's nonce value from the interaction finish response | |||
(Section 3.3.4) | ||||
* the "interact_ref" returned from the AS as part of the interaction | ||||
finish method (Section 4.2) | ||||
* the grant endpoint URL the client instance used to make its | ||||
initial request (Section 2) | ||||
There is no padding or whitespace before or after any of the lines, | ||||
and no trailing newline character. | ||||
VJLO6A4CAYLBXHTR0KRO | VJLO6A4CAYLBXHTR0KRO | |||
MBDOFXG4Y5CVJCX821LH | MBDOFXG4Y5CVJCX821LH | |||
4IFWWIKYBC2PQ6U56NL1 | 4IFWWIKYBC2PQ6U56NL1 | |||
https://server.example.com/tx | ||||
The party then hashes this string with the appropriate algorithm | The party then hashes this string with the appropriate algorithm | |||
based on the "hash_method" parameter of the "callback". If the | based on the "hash_method" parameter of the "callback". If the | |||
"hash_method" value is not present in the client instance's request, | "hash_method" value is not present in the client instance's request, | |||
the algorithm defaults to "sha3". | the algorithm defaults to "sha3". | |||
[[ See issue #56 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | [[ See issue #56 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | |||
issues/56) ]] | issues/56) ]] | |||
4.2.3.1. SHA3-512 | 4.2.3.1. SHA3-512 | |||
skipping to change at page 66, line 39 ¶ | skipping to change at page 65, line 48 ¶ | |||
Section 7.2 and present proof of the client instance's key (or its | Section 7.2 and present proof of the client instance's key (or its | |||
most recent rotation) by signing the request as described in | most recent rotation) by signing the request as described in | |||
Section 7.3. The AS MUST validate all keys presented by the client | Section 7.3. The AS MUST validate all keys presented by the client | |||
instance or referenced in an ongoing request for each call within | instance or referenced in an ongoing request for each call within | |||
that request. | that request. | |||
[[ See issue #85 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | [[ See issue #85 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | |||
issues/85) ]] | issues/85) ]] | |||
For example, here the client instance makes a POST request to a | For example, here the client instance makes a POST request to a | |||
unique URI and signs the request with detached JWS: | unique URI and signs the request with HTTP Message Signatures: | |||
POST /continue/KSKUOMUKM HTTP/1.1 | POST /continue/KSKUOMUKM HTTP/1.1 | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Host: server.example.com | Host: server.example.com | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
The AS MUST be able to tell from the client instance's request which | The AS MUST be able to tell from the client instance's request which | |||
specific ongoing request is being accessed, using a combination of | specific ongoing request is being accessed, using a combination of | |||
the continuation URL, the provided access token, and the client | the continuation URL, the provided access token, and the client | |||
instance identified by the key signature. If the AS cannot determine | instance identified by the key signature. If the AS cannot determine | |||
a single active grant request to map the continuation request to, the | a single active grant request to map the continuation request to, the | |||
AS MUST return an error. | AS MUST return an error. | |||
The ability to continue an already-started request allows the client | The ability to continue an already-started request allows the client | |||
instance to perform several important functions, including presenting | instance to perform several important functions, including presenting | |||
additional information from interaction, modifying the initial | additional information from interaction, modifying the initial | |||
request, and getting the current state of the request. | request, and getting the current state of the request. | |||
All requests to the continuation API are protected by this bound | All requests to the continuation API are protected by this bound | |||
access token. For example, here the client instance makes a POST | access token. For example, here the client instance makes a POST | |||
request to a stable continuation endpoint URL with the interaction | request to a stable continuation endpoint URL with the interaction | |||
reference (Section 5.1), includes the access token, and signs with | reference (Section 5.1), includes the access token, and signs with | |||
detached JWS: | HTTP Message Signatures: | |||
POST /continue HTTP/1.1 | POST /continue HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"interact_ref": "4IFWWIKYBC2PQ6U56NL1" | "interact_ref": "4IFWWIKYBC2PQ6U56NL1" | |||
} | } | |||
If a "wait" parameter was included in the continuation response | If a "wait" parameter was included in the continuation response | |||
(Section 3.1), the client instance MUST NOT call the continuation URI | (Section 3.1), the client instance MUST NOT call the continuation URI | |||
prior to waiting the number of seconds indicated. If no "wait" | prior to waiting the number of seconds indicated. If no "wait" | |||
period is indicated, the client instance SHOULD wait at least 5 | period is indicated, the client instance SHOULD wait at least 5 | |||
seconds. If the client instance does not respect the given wait | seconds. If the client instance does not respect the given wait | |||
skipping to change at page 68, line 16 ¶ | skipping to change at page 67, line 29 ¶ | |||
When the AS responds to the client instance's "finish" method as in | When the AS responds to the client instance's "finish" method as in | |||
Section 4.2.1, this response includes an interaction reference. The | Section 4.2.1, this response includes an interaction reference. The | |||
client instance MUST include that value as the field "interact_ref" | client instance MUST include that value as the field "interact_ref" | |||
in a POST request to the continuation URI. | in a POST request to the continuation URI. | |||
POST /continue HTTP/1.1 | POST /continue HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"interact_ref": "4IFWWIKYBC2PQ6U56NL1" | "interact_ref": "4IFWWIKYBC2PQ6U56NL1" | |||
} | } | |||
Since the interaction reference is a one-time-use value as described | Since the interaction reference is a one-time-use value as described | |||
in Section 4.2.1, if the client instance needs to make additional | in Section 4.2.1, if the client instance needs to make additional | |||
continuation calls after this request, the client instance MUST NOT | continuation calls after this request, the client instance MUST NOT | |||
include the interaction reference. If the AS detects a client | include the interaction reference. If the AS detects a client | |||
instance submitting the same interaction reference multiple times, | instance submitting the same interaction reference multiple times, | |||
skipping to change at page 69, line 37 ¶ | skipping to change at page 68, line 40 ¶ | |||
When the client instance does not include a "finish" parameter, the | When the client instance does not include a "finish" parameter, the | |||
client instance will often need to poll the AS until the RO has | client instance will often need to poll the AS until the RO has | |||
authorized the request. To do so, the client instance makes a POST | authorized the request. To do so, the client instance makes a POST | |||
request to the continuation URI as in Section 5.1, but does not | request to the continuation URI as in Section 5.1, but does not | |||
include a message body. | include a message body. | |||
POST /continue HTTP/1.1 | POST /continue HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
The Section 3 MAY contain any newly-created access tokens | The Section 3 MAY contain any newly-created access tokens | |||
(Section 3.2) or newly-released subject claims (Section 3.4). The | (Section 3.2) or newly-released subject claims (Section 3.4). The | |||
response MAY contain a new "continue" response (Section 3.1) as | response MAY contain a new "continue" response (Section 3.1) as | |||
described above. If a "continue" field is included, it SHOULD | described above. If a "continue" field is included, it SHOULD | |||
include a "wait" field to facilitate a reasonable polling rate by the | include a "wait" field to facilitate a reasonable polling rate by the | |||
client instance. The response SHOULD NOT contain interaction | client instance. The response SHOULD NOT contain interaction | |||
responses (Section 3.3). | responses (Section 3.3). | |||
For example, if the request has not yet been authorized by the RO, | For example, if the request has not yet been authorized by the RO, | |||
skipping to change at page 72, line 8 ¶ | skipping to change at page 71, line 8 ¶ | |||
contain a new "continue" response (Section 3.1) as described above. | contain a new "continue" response (Section 3.1) as described above. | |||
If interaction can occur, the response SHOULD contain interaction | If interaction can occur, the response SHOULD contain interaction | |||
responses (Section 3.3) as well. | responses (Section 3.3) as well. | |||
For example, a client instance initially requests a set of resources | For example, a client instance initially requests a set of resources | |||
using references: | using references: | |||
POST /tx HTTP/1.1 | POST /tx HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"read", "write" | "read", "write" | |||
] | ] | |||
}, | }, | |||
"interact": { | "interact": { | |||
"start": ["redirect"], | "start": ["redirect"], | |||
"finish": { | "finish": { | |||
skipping to change at page 73, line 9 ¶ | skipping to change at page 72, line 14 ¶ | |||
This "continue" field allows the client instance to make an eventual | This "continue" field allows the client instance to make an eventual | |||
continuation call. In the future, the client instance realizes that | continuation call. In the future, the client instance realizes that | |||
it no longer needs "write" access and therefore modifies its ongoing | it no longer needs "write" access and therefore modifies its ongoing | |||
request, here asking for just "read" access instead of both "read" | request, here asking for just "read" access instead of both "read" | |||
and "write" as before. | and "write" as before. | |||
PATCH /continue HTTP/1.1 | PATCH /continue HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"read" | "read" | |||
] | ] | |||
} | } | |||
... | ... | |||
} | } | |||
skipping to change at page 73, line 44 ¶ | skipping to change at page 73, line 4 ¶ | |||
"uri": "https://server.example.com/continue", | "uri": "https://server.example.com/continue", | |||
"wait": 30 | "wait": 30 | |||
}, | }, | |||
"access_token": { | "access_token": { | |||
"value": "0EVKC7-2ZKwZM_6N760", | "value": "0EVKC7-2ZKwZM_6N760", | |||
"access": [ | "access": [ | |||
"read" | "read" | |||
] | ] | |||
} | } | |||
} | } | |||
For another example, the client instance initially requests read-only | For another example, the client instance initially requests read-only | |||
access but later needs to step up its access. The initial request | access but later needs to step up its access. The initial request | |||
could look like this example. | could look like this example. | |||
POST /tx HTTP/1.1 | POST /tx HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"read" | "read" | |||
] | ] | |||
}, | }, | |||
"interact": { | "interact": { | |||
"start": ["redirect"], | "start": ["redirect"], | |||
"finish": { | "finish": { | |||
skipping to change at page 75, line 16 ¶ | skipping to change at page 74, line 22 ¶ | |||
and the callback is intended for one-time-use, a new one needs to be | and the callback is intended for one-time-use, a new one needs to be | |||
included in order to use the callback again. | included in order to use the callback again. | |||
[[ See issue #97 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | [[ See issue #97 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ | |||
issues/97) ]] | issues/97) ]] | |||
PATCH /continue HTTP/1.1 | PATCH /continue HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"read", "write" | "read", "write" | |||
] | ] | |||
}, | }, | |||
"interact": { | "interact": { | |||
"start": ["redirect"], | "start": ["redirect"], | |||
"finish": { | "finish": { | |||
skipping to change at page 76, line 9 ¶ | skipping to change at page 75, line 14 ¶ | |||
5.4. Canceling a Grant Request | 5.4. Canceling a Grant Request | |||
If the client instance wishes to cancel an ongoing grant request, it | If the client instance wishes to cancel an ongoing grant request, it | |||
makes an HTTP DELETE request to the continuation URI. | makes an HTTP DELETE request to the continuation URI. | |||
DELETE /continue HTTP/1.1 | DELETE /continue HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
If the request is successfully cancelled, the AS responds with an | If the request is successfully cancelled, the AS responds with an | |||
HTTP 202. The AS SHOULD revoke all associated access tokens. | HTTP 202. The AS SHOULD revoke all associated access tokens. | |||
6. Token Management | 6. Token Management | |||
If an access token response includes the "manage" parameter as | If an access token response includes the "manage" parameter as | |||
described in Section 3.2.1, the client instance MAY call this URL to | described in Section 3.2.1, the client instance MAY call this URL to | |||
manage the access token with any of the actions defined in the | manage the access token with any of the actions defined in the | |||
following sections. Other actions are undefined by this | following sections. Other actions are undefined by this | |||
skipping to change at page 76, line 47 ¶ | skipping to change at page 76, line 8 ¶ | |||
6.1. Rotating the Access Token | 6.1. Rotating the Access Token | |||
The client instance makes an HTTP POST to the token management URI, | The client instance makes an HTTP POST to the token management URI, | |||
sending the access token in the appropriate header and signing the | sending the access token in the appropriate header and signing the | |||
request with the appropriate key. | request with the appropriate key. | |||
POST /token/PRY5NM33OM4TB8N6BW7OZB8CDFONP219RP1L HTTP/1.1 | POST /token/PRY5NM33OM4TB8N6BW7OZB8CDFONP219RP1L HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Authorization: GNAP OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 | Authorization: GNAP OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 | |||
Detached-JWS: eyj0.... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
The AS validates that the token presented is associated with the | The AS validates that the token presented is associated with the | |||
management URL, that the AS issued the token to the given client | management URL, that the AS issued the token to the given client | |||
instance, and that the presented key is appropriate to the token. | instance, and that the presented key is appropriate to the token. | |||
If the access token has expired, the AS SHOULD honor the rotation | If the access token has expired, the AS SHOULD honor the rotation | |||
request to the token management URL since it is likely that the | request to the token management URL since it is likely that the | |||
client instance is attempting to refresh the expired token. To | client instance is attempting to refresh the expired token. To | |||
support this, the AS MAY apply different lifetimes for the use of the | support this, the AS MAY apply different lifetimes for the use of the | |||
token in management vs. its use at an RS. An AS MUST NOT honor a | token in management vs. its use at an RS. An AS MUST NOT honor a | |||
skipping to change at page 78, line 50 ¶ | skipping to change at page 77, line 50 ¶ | |||
token management URI to indicate to the AS that the AS should | token management URI to indicate to the AS that the AS should | |||
invalidate the access token for all purposes. | invalidate the access token for all purposes. | |||
The client instance makes an HTTP DELETE request to the token | The client instance makes an HTTP DELETE request to the token | |||
management URI, presenting the access token and signing the request | management URI, presenting the access token and signing the request | |||
with the appropriate key. | with the appropriate key. | |||
DELETE /token/PRY5NM33OM4TB8N6BW7OZB8CDFONP219RP1L HTTP/1.1 | DELETE /token/PRY5NM33OM4TB8N6BW7OZB8CDFONP219RP1L HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Authorization: GNAP OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 | Authorization: GNAP OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 | |||
Detached-JWS: eyj0.... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
If the key presented is associated with the token (or the client | If the key presented is associated with the token (or the client | |||
instance, in the case of a bearer token), the AS MUST invalidate the | instance, in the case of a bearer token), the AS MUST invalidate the | |||
access token, if possible, and return an HTTP 204 response code. | access token, if possible, and return an HTTP 204 response code. | |||
204 No Content | 204 No Content | |||
Though the AS MAY revoke an access token at any time for any reason, | Though the AS MAY revoke an access token at any time for any reason, | |||
the token management function is specifically for the client | the token management function is specifically for the client | |||
instance's use. If the access token has already expired or has been | instance's use. If the access token has already expired or has been | |||
skipping to change at page 79, line 38 ¶ | skipping to change at page 78, line 38 ¶ | |||
* When a key proof is used with no access token, this is a non- | * When a key proof is used with no access token, this is a non- | |||
authorized signed request. This type of request is used for calls | authorized signed request. This type of request is used for calls | |||
to the AS to initiate a negotiation. | to the AS to initiate a negotiation. | |||
* When an access token is used with no key proof, this is a bearer | * When an access token is used with no key proof, this is a bearer | |||
token request. This type of request is used only for calls to the | token request. This type of request is used only for calls to the | |||
RS, and only with access tokens that are not bound to any key as | RS, and only with access tokens that are not bound to any key as | |||
described in Section 3.2.1. | described in Section 3.2.1. | |||
* When neither an access token nor key proof are used, this is an | * When neither an access token nor key proof are used, this is an | |||
unsecured request. This type of request is not used in the core | unsecured request. This type of request is used optionally for | |||
protocol of GNAP. | calls to the RS as part of an RS-first discovery process as | |||
described in Section 9.1. | ||||
7.1. Key Formats | 7.1. Key Formats | |||
Several different places in GNAP require the presentation of key | Several different places in GNAP require the presentation of key | |||
material by value. Proof of this key material MUST be bound to a | material by value. Proof of this key material MUST be bound to a | |||
request, the nature of which varies with the location in the protocol | request, the nature of which varies with the location in the protocol | |||
the key is used. For a key used as part of a client instance's | the key is used. For a key used as part of a client instance's | |||
initial request in Section 2.3, the key value is the client | initial request in Section 2.3, the key value is the client | |||
instance's public key, and proof of that key MUST be presented in | instance's public key, and proof of that key MUST be presented in | |||
that request. For a key used as part of an access token response in | that request. For a key used as part of an access token response in | |||
skipping to change at page 80, line 33 ¶ | skipping to change at page 79, line 33 ¶ | |||
the request, with optional internal whitespace per [RFC7468]. The | the request, with optional internal whitespace per [RFC7468]. The | |||
PEM header and footer are optionally removed. | PEM header and footer are optionally removed. | |||
cert#S256 (string) The certificate thumbprint calculated as per | cert#S256 (string) The certificate thumbprint calculated as per | |||
OAuth-MTLS [RFC8705] in base64 URL encoding. Note that this | OAuth-MTLS [RFC8705] in base64 URL encoding. Note that this | |||
format does not include the full public key. | format does not include the full public key. | |||
Additional key formats are defined in a registry TBD (Section 11). | Additional key formats are defined in a registry TBD (Section 11). | |||
This non-normative example shows a single key presented in multiple | This non-normative example shows a single key presented in multiple | |||
formats. This key is intended to be used with the detached JWS | formats. This example key is intended to be used with the HTTP | |||
(Section 7.3.1) proofing mechanism, as indicated by the "proof" | Message Signatures ({{httpsig-binding}}) proofing mechanism, as | |||
field. | indicated by the "httpsig" value of the "proof" field. | |||
"key": { | "key": { | |||
"proof": "jwsd", | "proof": "httpsig", | |||
"jwk": { | "jwk": { | |||
"kty": "RSA", | "kty": "RSA", | |||
"e": "AQAB", | "e": "AQAB", | |||
"kid": "xyz-1", | "kid": "xyz-1", | |||
"alg": "RS256", | "alg": "RS256", | |||
"n": "kOB5rR4Jv0GMeLaY6_It_r3ORwdf8ci_JtffXyaSx8xY..." | "n": "kOB5rR4Jv0GMeLaY6_It_r3ORwdf8ci_JtffXyaSx8xY..." | |||
}, | }, | |||
"cert": "MIIEHDCCAwSgAwIBAgIBATANBgkqhkiG9w0BAQsFA..." | "cert": "MIIEHDCCAwSgAwIBAgIBATANBgkqhkiG9w0BAQsFA..." | |||
} | } | |||
skipping to change at page 81, line 31 ¶ | skipping to change at page 80, line 31 ¶ | |||
specification. | specification. | |||
7.2. Presenting Access Tokens | 7.2. Presenting Access Tokens | |||
The method the client instance uses to send an access token depends | The method the client instance uses to send an access token depends | |||
on whether the token is bound to a key, and if so which proofing | on whether the token is bound to a key, and if so which proofing | |||
method is associated with the key. This information is conveyed in | method is associated with the key. This information is conveyed in | |||
the "bound" and "key" parameters in the single (Section 3.2.1) and | the "bound" and "key" parameters in the single (Section 3.2.1) and | |||
multiple access tokens (Section 3.2.2) responses. | multiple access tokens (Section 3.2.2) responses. | |||
If the "bound" value is the boolean "true" and the "key" is absent, | If the "flags" field does not contain the "bearer" flag and the "key" | |||
the access token MUST be sent using the same key and proofing | is absent, the access token MUST be sent using the same key and | |||
mechanism that the client instance used in its initial request (or | proofing mechanism that the client instance used in its initial | |||
its most recent rotation). | request (or its most recent rotation). | |||
If the "bound" value is the boolean "true" and the "key" value is an | If the "flags" field does not contain the "bearer" flag and the "key" | |||
object as described in Section 7.1, the access token MUST be sent | value is an object as described in Section 7.1, the access token MUST | |||
using the key and proofing mechanism defined by the value of the | be sent using the key and proofing mechanism defined by the value of | |||
"proof" field within the key object. | the "proof" field within the key object. | |||
The access token MUST be sent using the HTTP "Authorization" request | The access token MUST be sent using the HTTP "Authorization" request | |||
header field and the "GNAP" authorization scheme along with a key | header field and the "GNAP" authorization scheme along with a key | |||
proof as described in Section 7.3 for the key bound to the access | proof as described in Section 7.3 for the key bound to the access | |||
token. For example, a "jwsd"-bound access token is sent as follows: | token. For example, an "httpsig"-bound access token is sent as | |||
follows: | ||||
Authorization: GNAP OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 | Authorization: GNAP OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 | |||
Detached-JWS: eyj0.... | Signature-Input: sig1=(authorization);... | |||
Signature: sig1=... | ||||
If the "bound" value is the boolean "false", the access token is a | If the "flags" field contains the "bearer" flag, the access token is | |||
bearer token that MUST be sent using the "Authorization Request | a bearer token that MUST be sent using the "Authorization Request | |||
Header Field" method defined in [RFC6750]. | Header Field" method defined in [RFC6750]. | |||
Authorization: Bearer OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 | Authorization: Bearer OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 | |||
The "Form-Encoded Body Parameter" and "URI Query Parameter" methods | The "Form-Encoded Body Parameter" and "URI Query Parameter" methods | |||
of [RFC6750] MUST NOT be used. | of [RFC6750] MUST NOT be used. | |||
[[ See issue #104 (https://github.com/ietf-wg-gnap/gnap-core- | [[ See issue #104 (https://github.com/ietf-wg-gnap/gnap-core- | |||
protocol/issues/104) ]] | protocol/issues/104) ]] | |||
The client software MUST reject as an error a situation where the | The client software MUST reject as an error a situation where the | |||
"bound" value is the boolean "false" and the "key" is present. | "flags" field contains the "bearer" flag and the "key" field is | |||
present with any value. | ||||
7.3. Proving Possession of a Key with a Request | 7.3. Proving Possession of a Key with a Request | |||
Any keys presented by the client instance to the AS or RS MUST be | Any keys presented by the client instance to the AS or RS MUST be | |||
validated as part of the request in which they are presented. The | validated as part of the request in which they are presented. The | |||
type of binding used is indicated by the proof parameter of the key | type of binding used is indicated by the proof parameter of the key | |||
object in Section 7.1. Values defined by this specification are as | object in Section 7.1. Values defined by this specification are as | |||
follows: | follows: | |||
jwsd A detached JWS signature header | httpsig HTTP Signing signature header | |||
jws Attached JWS payload | ||||
mtls Mutual TLS certificate verification | mtls Mutual TLS certificate verification | |||
dpop OAuth Demonstration of Proof-of-Possession key proof header | jwsd A detached JWS signature header | |||
httpsig HTTP Signing signature header | ||||
oauthpop OAuth PoP key proof authentication header | jws Attached JWS payload | |||
Additional proofing methods are defined by a registry TBD | Additional proofing methods are defined by a registry TBD | |||
(Section 11). | (Section 11). | |||
All key binding methods used by this specification MUST cover all | All key binding methods used by this specification MUST cover all | |||
relevant portions of the request, including anything that would | relevant portions of the request, including anything that would | |||
change the nature of the request, to allow for secure validation of | change the nature of the request, to allow for secure validation of | |||
the request. Relevant aspects include the URI being called, the HTTP | the request. Relevant aspects include the URI being called, the HTTP | |||
method being used, any relevant HTTP headers and values, and the HTTP | method being used, any relevant HTTP headers and values, and the HTTP | |||
message body itself. The verifier of the signed message MUST | message body itself. The verifier of the signed message MUST | |||
skipping to change at page 84, line 39 ¶ | skipping to change at page 83, line 39 ¶ | |||
M40ql8u8J6vc2GmQGfokLlPQ6XLSCY68_xkTXrhoU1f-eDntkhP7L6XawSK\ | M40ql8u8J6vc2GmQGfokLlPQ6XLSCY68_xkTXrhoU1f-eDntkhP7L6XawSK\ | |||
Onv5F2H7wyBQ75HUmHTg8AK2B_vRlMyFKjXbVlzKf4kvqChSGEz4IjQ", | Onv5F2H7wyBQ75HUmHTg8AK2B_vRlMyFKjXbVlzKf4kvqChSGEz4IjQ", | |||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8BfYdHsFzAt\ | "n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8BfYdHsFzAt\ | |||
YKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZGYX\ | YKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZGYX\ | |||
jHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZx\ | jHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZx\ | |||
e0jRETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0\ | e0jRETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0\ | |||
bunS0K3bA_3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kO\ | bunS0K3bA_3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kO\ | |||
zywzwPTuq-cVQDyEN7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | zywzwPTuq-cVQDyEN7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | |||
} | } | |||
7.3.1. Detached JWS | 7.3.1. HTTP Message Signing | |||
This method is indicated by "jwsd" in the "proof" field. A JWS | ||||
[RFC7515] object is created as follows: | ||||
To protect the request, the JOSE header of the signature contains the | ||||
following parameters: | ||||
kid (string) The key identifier. RECOMMENDED. If the key is | ||||
presented in JWK format, this MUST be the value of the "kid" field | ||||
of the key. | ||||
alg (string) The algorithm used to sign the request. REQUIRED. | ||||
MUST be appropriate to the key presented. If the key is presented | ||||
as a JWK, this MUST be equal to the "alg" parameter of the key. | ||||
MUST NOT be "none". | ||||
typ (string) The type header, value "gnap-binding+jwsd". REQUIRED | ||||
htm (string) The HTTP Method used to make this request, as an | This method is indicated by "httpsig" in the "proof" field. The | |||
uppercase ASCII string. REQUIRED | sender creates an HTTP Message Signature as described in | |||
[I-D.ietf-httpbis-message-signatures]. | ||||
uri (string) The HTTP URI used for this request, including all path | The covered content of the signature MUST include the following: | |||
and query components and no fragment component. REQUIRED | ||||
created (integer) A timestamp of when the signature was created, in | @request-target: the target of the HTTP request | |||
integer seconds since UNIX Epoch | ||||
ath (string) When a request is bound to an access token, the access | digest: The Digest header as defined in [RFC3230]. When the request | |||
token hash value. The value MUST be the result of Base64url | message has a body, the signer MUST calculate this header value | |||
encoding (with no padding) the SHA-256 digest of the ASCII | and the verifier MUST validate this header. | |||
encoding of the associated access token's value. REQUIRED if the | ||||
request protects an access token. | ||||
If the HTTP request has a message body, such as an HTTP POST or PUT | When the request is bound to an access token, the covered content | |||
method, the payload of the JWS object is the Base64url encoding | MUST also include: | |||
(without padding) of the SHA256 digest of the bytes of the body. If | ||||
the request being made does not have a message body, such as an HTTP | ||||
GET, OPTIONS, or DELETE method, the JWS signature is calculated over | ||||
an empty payload. | ||||
The client instance presents the signed object in compact form | authorization: The Authorization header used to present the access | |||
[RFC7515] in the Detached-JWS HTTP Header field. | token as discussed in Section 7.2. | |||
In this example, the JOSE Header contains the following parameters: | Other covered content MAY also be included. | |||
{ | If the signer's key presented is a JWK, the "keyid" parameter of the | |||
"alg": "RS256", | signature MUST be set to the "kid" value of the JWK, the signing | |||
"kid": "gnap-rsa", | algorithm used MUST be the JWS algorithm denoted by the key's "alg" | |||
"uri": "https://server.example.com/gnap", | field, and the explicit "alg" signature parameter MUST NOT be | |||
"htm": "POST", | included. | |||
"typ": "gnap-binding+jwsd", | ||||
"created": 1618884475 | ||||
} | ||||
The request body is the following JSON object: | In this example, the message body is the following JSON object: | |||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"dolphin-metadata" | "dolphin-metadata" | |||
] | ] | |||
}, | }, | |||
"interact": { | "interact": { | |||
"start": ["redirect"], | "start": ["redirect"], | |||
"finish": { | "finish": { | |||
"method": "redirect", | "method": "redirect", | |||
"uri": "https://client.foo/callback", | "uri": "https://client.foo/callback", | |||
"nonce": "VJLO6A4CAYLBXHTR0KRO" | "nonce": "VJLO6A4CAYLBXHTR0KRO" | |||
} | } | |||
}, | }, | |||
"client": { | "client": { | |||
"proof": "jwsd", | "proof": "httpsig", | |||
"key": { | "key": { | |||
"jwk": { | "jwk": { | |||
"kid": "gnap-rsa", | "kid": "gnap-rsa", | |||
"kty": "RSA", | "kty": "RSA", | |||
"e": "AQAB", | "e": "AQAB", | |||
"alg": "RS256", | "alg": "RS256", | |||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | "n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | |||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | |||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | |||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | |||
skipping to change at page 86, line 42 ¶ | skipping to change at page 85, line 42 ¶ | |||
N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | |||
} | } | |||
} | } | |||
"display": { | "display": { | |||
"name": "My Client Display Name", | "name": "My Client Display Name", | |||
"uri": "https://client.foo/" | "uri": "https://client.foo/" | |||
}, | }, | |||
} | } | |||
} | } | |||
This is hashed to the following Base64 encoded value: | This body is hashed for the Digest header using SHA-256 into the | |||
following encoded value: | ||||
PGiVuOZUcN1tRtUS6tx2b4cBgw9mPgXG3IPB3wY7ctc | SHA-256=98QzyNVYpdgTrWBKpC4qFSCmmR+CrwwvUoiaDCSjKxw= | |||
This leads to the following full HTTP request message: | The HTTP message signature input string is calculated to be the | |||
following: | ||||
"@request-target": post /gnap | ||||
"host": server.example.com | ||||
"content-type": application/json | ||||
"digest": SHA-256=98QzyNVYpdgTrWBKpC4qFSCmmR+CrwwvUoiaDCSjKxw= | ||||
"content-length": 986 | ||||
"@signature-params": ("@request-target" "host" "content-type" \ | ||||
"digest" "content-length");created=1618884475;keyid="gnap-rsa" | ||||
This leads to the following full HTTP message request: | ||||
POST /gnap HTTP/1.1 | POST /gnap HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Content-Length: 983 | Content-Length: 986 | |||
Detached-JWS: eyJhbGciOiJSUzI1NiIsImNyZWF0ZWQiOjE2MTg4ODQ0NzUsImh0b\ | Digest: SHA-256=98QzyNVYpdgTrWBKpC4qFSCmmR+CrwwvUoiaDCSjKxw= | |||
SI6IlBPU1QiLCJraWQiOiJnbmFwLXJzYSIsInR5cCI6ImduYXAtYmluZGluZytqd3\ | Signature-Input: sig1=("@request-target" "host" "content-type" \ | |||
NkIiwidXJpIjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20vZ25hcCJ9.PGiVuO\ | "digest" "content-length");created=1618884475;keyid="gnap-rsa" | |||
ZUcN1tRtUS6tx2b4cBgw9mPgXG3IPB3wY7ctc.fUq-SV-A1iFN2MwCRW_yolVtT2_\ | Signature: \ | |||
TZA2h5YeXUoi5F2Q2iToC0Tc4drYFOSHIX68knd68RUA7yHqCVP-ZQEd6aL32H69e\ | sig1=:axj8FLOvEWBcwh+Xk6VTTKXxqo4XNygleTDJ8h3ZJfi1sSmWrRtyo9RG/dc\ | |||
9zuMiw6O_s4TBKB3vDOvwrhYtDH6fX2hP70cQoO-47OwbqP-ifkrvI3hVgMX9TfjV\ | miZmdszRjWbg+/ixVZpA4BL3AOwEOxxtmHAXNB8uJ0I3tfbs6Suyk4sEo8zPr+MJq\ | |||
eKNwnhoNnw3vbu7SNKeqJEbbwZfpESaGepS52xNBlDNMYBQQXxM9OqKJaXffzLFEl\ | MjxdJEUgAQAy2AH+wg5a7CKq4IdLTulFK9njUIeG7MygHumeiumM3DbDQAHgF46dV\ | |||
-Xe0UnfolVtBraz3aPrPy1C6a4uT7wLda3PaTOVtgysxzii3oJWpuz0WP5kRujzDF\ | q5UC6KJnqhGM1rFC128jd2D0sgWKCUgKGCHtfR159zfKWcEO9krsLoOnCdTzm1UyD\ | |||
wX_EOzW0jsjCSkL-PXaKSpZgEjNjKDMg9irSxUISt1C1T6q3SzRgfuQ | DMjkIjqeN/1j8PdMJaRAwV4On079O0DVu6bl1jVtkzo/e/ZmwPr/X436V4xiw/hZt\ | |||
w4sfNsSbmsT0+UAQ20X/xaw==: | ||||
{ | ||||
"access_token": { | ||||
"access": [ | ||||
"dolphin-metadata" | ||||
] | ||||
}, | ||||
"interact": { | ||||
"start": ["redirect"], | ||||
"finish": { | ||||
"method": "redirect", | ||||
"uri": "https://client.foo/callback", | ||||
"nonce": "VJLO6A4CAYLBXHTR0KRO" | ||||
} | ||||
}, | ||||
"client": { | ||||
"proof": "jwsd", | ||||
"key": { | ||||
"jwk": { | ||||
"kid": "gnap-rsa", | ||||
"kty": "RSA", | ||||
"e": "AQAB", | ||||
"alg": "RS256", | ||||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | ||||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | ||||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | ||||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ||||
3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | ||||
N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | ||||
} | ||||
} | ||||
"display": { | ||||
"name": "My Client Display Name", | ||||
"uri": "https://client.foo/" | ||||
}, | ||||
} | ||||
} | ||||
When the verifier receives the Detached-JWS header, it MUST parse and | ||||
validate the JWS object. The signature MUST be validated against the | ||||
expected key of the signer. All required fields MUST be present and | ||||
their values MUST be valid. If the HTTP message request contains a | ||||
body, the verifier MUST calculate the hash of body just as the signer | ||||
does, with no normalization or transformation of the request. | ||||
7.3.2. Attached JWS | ||||
This method is indicated by "jws" in the "proof" field. A JWS | ||||
[RFC7515] object is created as follows: | ||||
The JOSE header MUST contain the "kid" parameter of the key bound to | ||||
this client instance for this request. The "alg" parameter MUST be | ||||
set to a value appropriate for the key identified by kid and MUST NOT | ||||
be "none". | ||||
To protect the request, the JWS header MUST contain the following | ||||
additional parameters. | ||||
typ (string) The type header, value "gnap-binding+jws". | ||||
htm (string) The HTTP Method used to make this request, as an | ||||
uppercase ASCII string. | ||||
uri (string) The HTTP URI used for this request, including all path | ||||
and query components and no fragment component. | ||||
created (integer) A timestamp of when the signature was created, in | ||||
integer seconds since UNIX Epoch | ||||
ath (string) When a request is bound to an access token, the access | ||||
token hash value. The value MUST be the result of Base64url | ||||
encoding (with no padding) the SHA-256 digest of the ASCII | ||||
encoding of the associated access token's value. | ||||
If the HTTP request has a message body, such as an HTTP POST or PUT | ||||
method, the payload of the JWS object is the JSON serialized body of | ||||
the request, and the object is signed according to JWS and serialized | ||||
into compact form [RFC7515]. The client instance presents the JWS as | ||||
the body of the request along with a content type of "application/ | ||||
jose". The AS MUST extract the payload of the JWS and treat it as | ||||
the request body for further processing. | ||||
If the request being made does not have a message body, such as an | ||||
HTTP GET, OPTIONS, or DELETE method, the JWS signature is calculated | ||||
over an empty payload and passed in the "Detached-JWS" header as | ||||
described in Section 7.3.1. | ||||
In this example, the JOSE header contains the following parameters: | ||||
{ | ||||
"alg": "RS256", | ||||
"kid": "gnap-rsa", | ||||
"uri": "https://server.example.com/gnap", | ||||
"htm": "POST", | ||||
"typ": "gnap-binding+jwsd", | ||||
"created": 1618884475 | ||||
} | ||||
The request body, used as the JWS Payload, is the following JSON | ||||
object: | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"dolphin-metadata" | "dolphin-metadata" | |||
] | ] | |||
}, | }, | |||
"interact": { | "interact": { | |||
"start": ["redirect"], | "start": ["redirect"], | |||
"finish": { | "finish": { | |||
"method": "redirect", | "method": "redirect", | |||
"uri": "https://client.foo/callback", | "uri": "https://client.foo/callback", | |||
"nonce": "VJLO6A4CAYLBXHTR0KRO" | "nonce": "VJLO6A4CAYLBXHTR0KRO" | |||
} | } | |||
}, | }, | |||
"client": { | "client": { | |||
"proof": "jws", | "proof": "httpsig", | |||
"key": { | "key": { | |||
"jwk": { | "jwk": { | |||
"kid": "gnap-rsa", | "kid": "gnap-rsa", | |||
"kty": "RSA", | "kty": "RSA", | |||
"e": "AQAB", | "e": "AQAB", | |||
"alg": "RS256", | "alg": "RS256", | |||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | "n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | |||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | |||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | |||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | |||
3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | 3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | |||
N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | |||
} | } | |||
} | } | |||
"display": { | "display": { | |||
"name": "My Client Display Name", | "name": "My Client Display Name", | |||
"uri": "https://client.foo/" | "uri": "https://client.foo/" | |||
}, | }, | |||
}, | ||||
"subject": { | ||||
"formats": ["iss_sub", "opaque"] | ||||
} | } | |||
} | } | |||
This leads to the following full HTTP request message: | If the HTTP Message includes a message body, the verifier MUST | |||
calculate and verify the value of the "Digest" header. The verifier | ||||
POST /gnap HTTP/1.1 | MUST ensure that the signature includes all required covered content. | |||
Host: server.example.com | The verifier MUST validate the signature against the expected key of | |||
Content-Type: application/jose | the signer. | |||
Content-Length: 1047 | ||||
eyJhbGciOiJSUzI1NiIsImNyZWF0ZWQiOjE2MTg4ODQ0NzUsImh0bSI6IlBPU1QiLCJ\ | ||||
raWQiOiJnbmFwLXJzYSIsInR5cCI6ImduYXAtYmluZGluZytqd3NkIiwidXJpIjoiaH\ | ||||
R0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20vZ25hcCJ9.CnsKICAgICJhY2Nlc3NfdG9r\ | ||||
ZW4iOiB7CiAgICAgICAgImFjY2VzcyI6IFsKICAgICAgICAgICAgImRvbHBoaW4tbWV\ | ||||
0YWRhdGEiCiAgICAgICAgXQogICAgfSwKICAgICJpbnRlcmFjdCI6IHsKICAgICAgIC\ | ||||
Aic3RhcnQiOiBbInJlZGlyZWN0Il0sCiAgICAgICAgImZpbmlzaCI6IHsKICAgICAgI\ | ||||
CAgICAgIm1ldGhvZCI6ICJyZWRpcmVjdCIsCiAgICAgICAgICAgICJ1cmkiOiAiaHR0\ | ||||
cHM6Ly9jbGllbnQuZm9vL2NhbGxiYWNrIiwKICAgICAgICAgICAgIm5vbmNlIjogIlZ\ | ||||
KTE82QTRDQVlMQlhIVFIwS1JPIgogICAgICAgIH0KICAgIH0sCiAgICAiY2xpZW50Ij\ | ||||
ogewogICAgICAicHJvb2YiOiAiandzIiwKICAgICAgImtleSI6IHsKICAgICAgICAia\ | ||||
ndrIjogewogICAgICAgICAgICAia2lkIjogImduYXAtcnNhIiwKICAgICAgICAgICAg\ | ||||
Imt0eSI6ICJSU0EiLAogICAgICAgICAgICAiZSI6ICJBUUFCIiwKICAgICAgICAgICA\ | ||||
gImFsZyI6ICJSUzI1NiIsCiAgICAgICAgICAgICJuIjogImhZT0otWE9LSVNkTU1TaG\ | ||||
5fRzRXOW0yMG1UMFZXdFFCc21CQmtJMmNtUnQ0QWk4QmZZZEhzRnpBdFlLT2pwQlIxU\ | ||||
nBLcEptVkt4SUdOeTBnNlozYWQyWFlzaDhLb3dseVZ5OElrWjhOTXdTcmNVSUJaR1lY\ | ||||
akhwd2p6dmZHdlhIXzVLSmxuUjNfdVJVcDRaNFVqazJiQ2FLZWdEbjExVjJ2eEU0MWh\ | ||||
xYVBVbmhSWnhlMGpSRVRkZHpzRTNtdTFTSzhkVENST2p3VWwxNG1VTm84aVRyVG00bj\ | ||||
BxRGFkejhCa1BvLXV2NEJDMGJ1blMwSzNiQV8zVWdWcDd6QmxRRm9GbkxUTzJ1V3Bfb\ | ||||
XVMRVdHbDY3Z0JxOU1PM2JyS1hmR2hpM2tPenl3endQVHVxLWNWUUR5RU43YUwwU3hD\ | ||||
YjNIYzRJZHFEYU1nOHFIVXlPYnBQaXREUSIKICAgICAgICB9CiAgICAgIH0KICAgICA\ | ||||
gImRpc3BsYXkiOiB7CiAgICAgICAgIm5hbWUiOiAiTXkgQ2xpZW50IERpc3BsYXkgTm\ | ||||
FtZSIsCiAgICAgICAgInVyaSI6ICJodHRwczovL2NsaWVudC5mb28vIgogICAgICB9L\ | ||||
AogICAgfSwKICAgICJzdWJqZWN0IjogewogICAgICAgICJmb3JtYXRzIjogWyJpc3Nf\ | ||||
c3ViIiwgIm9wYXF1ZSJdCiAgICB9Cn0K.MwNoVMQp5hVxI0mCs9LlOUdFtkDXaA1_eT\ | ||||
vOXq7DOGrtDKH7q4vP2xUq3fH2jRAZqnobo0WdPP3eM3NH5QUjW8pa6_QpwdIWkK7r-\ | ||||
u_52puE0lPBp7J4U2w4l9gIbg8iknsmWmXeY5F6wiGT8ptfuEYGgmloAJd9LIeNvD3U\ | ||||
LW2h2dz1Pn2eDnbyvgB0Ugae0BoZB4f69fKWj8Z9wvTIjk1LZJN1PcL7_zT8Lrlic9a\ | ||||
PyzT7Q9ovkd1s-4whE7TrnGUzFc5mgWUn_gsOpsP5mIIljoEEv-FqOW2RyNYulOZl0Q\ | ||||
8EnnDHV_vPzrHlUarbGg4YffgtwkQhdK72-JOxYQ | ||||
[[ See issue #109 (https://github.com/ietf-wg-gnap/gnap-core- | ||||
protocol/issues/109) ]] | ||||
When the verifier receives an attached JWS request, it MUST parse and | ||||
validate the JWS object. The signature MUST be validated against the | ||||
expected key of the signer. All required fields MUST be present and | ||||
their values MUST be valid. If the HTTP message request contains a | ||||
body, the verifier MUST decode the payload of the JWS object and | ||||
treat this as the HTTP message body. | ||||
7.3.3. Mutual TLS | 7.3.2. Mutual TLS | |||
This method is indicated by "mtls" in the "proof" field. The signer | This method is indicated by "mtls" in the "proof" field. The signer | |||
presents its TLS client certificate during TLS negotiation with the | presents its TLS client certificate during TLS negotiation with the | |||
verifier. | verifier. | |||
In this example, the certificate is communicated to the application | In this example, the certificate is communicated to the application | |||
through the "Client-Cert" header from a TLS reverse proxy, leading to | through the "Client-Cert" header from a TLS reverse proxy, leading to | |||
the following full HTTP request message: | the following full HTTP request message: | |||
POST /gnap HTTP/1.1 | POST /gnap HTTP/1.1 | |||
skipping to change at page 94, line 5 ¶ | skipping to change at page 89, line 21 ¶ | |||
Note that in many instances, the verifier will not do a full | Note that in many instances, the verifier will not do a full | |||
certificate chain validation of the presented TLS client certificate, | certificate chain validation of the presented TLS client certificate, | |||
as the means of trust for this certificate could be in something | as the means of trust for this certificate could be in something | |||
other than a PKI system, such as a static registration or trust-on- | other than a PKI system, such as a static registration or trust-on- | |||
first-use. | first-use. | |||
[[ See issue #110 (https://github.com/ietf-wg-gnap/gnap-core- | [[ See issue #110 (https://github.com/ietf-wg-gnap/gnap-core- | |||
protocol/issues/110) ]] | protocol/issues/110) ]] | |||
7.3.4. Demonstration of Proof-of-Possession (DPoP) | 7.3.3. Detached JWS | |||
This method is indicated by "dpop" in the "proof" field. The signer | ||||
creates a Demonstration of Proof-of-Possession signature header as | ||||
described in [I-D.ietf-oauth-dpop] section 2. In addition, this | ||||
specification defines the following fields to be added to the DPoP | ||||
payload: | ||||
htd (string) Digest of the request body as the value of the Digest | ||||
header defined in [RFC3230]. When a request contains a message | ||||
body, such as a POST or PUT request, this field is REQUIRED. | ||||
In this example, the request body is the following JSON object: ~~~ { | ||||
"access_token": { "access": [ "dolphin-metadata" ] }, "interact": { | ||||
"start": ["redirect"], "finish": { "method": "redirect", "uri": | ||||
"https://client.foo/callback", "nonce": "VJLO6A4CAYLBXHTR0KRO" } }, | ||||
"client": { "proof": "dpop", "key": { "jwk": { "kid": "gnap-rsa", | ||||
"kty": "RSA", "e": "AQAB", "alg": "RS256", "n": "hYOJ- | ||||
XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | ||||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | ||||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | ||||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ||||
3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | ||||
N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" } } "display": { "name": "My | ||||
Client Display Name", "uri": "https://client.foo/" }, } } ~~~ | ||||
The JOSE header contains the following parameters, including the | ||||
public key: | ||||
{ | ||||
"alg": "RS256", | ||||
"typ": "dpop+jwt", | ||||
"jwk": { | ||||
"kid": "gnap-rsa", | ||||
"kty": "RSA", | ||||
"e": "AQAB", | ||||
"alg": "RS256", | ||||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8BfYdHs\ | ||||
FzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZGYXjH\ | ||||
pwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jRETdd\ | ||||
zsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_3UgV\ | ||||
p7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyEN7aL\ | ||||
0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | ||||
} | ||||
} | ||||
The JWS Payload contains the following JWT claims, including a hash | ||||
of the body: | ||||
{ | ||||
"htu": "https://server.example.com/gnap", | ||||
"htm": "POST", | ||||
"iat": 1618884475, | ||||
"jti": "HjoHrjgm2yB4x7jA5yyG", | ||||
"htd": "SHA-256=tnPQ2GXm8r/rTTKdbQ8pc7EjiFFPy1ExSX6OZVG3JVI=" | ||||
} | ||||
This results in the following full HTTP message request: | This method is indicated by "jwsd" in the "proof" field. A JWS | |||
[RFC7515] object is created as follows: | ||||
POST /gnap HTTP/1.1 | To protect the request, the JOSE header of the signature contains the | |||
Host: server.example.com | following parameters: | |||
Content-Type: application/json | ||||
Content-Length: 983 | ||||
DPoP: eyJhbGciOiJSUzI1NiIsImp3ayI6eyJhbGciOiJSUzI1NiIsImUiOiJBUUFCI\ | ||||
iwia2lkIjoiZ25hcC1yc2EiLCJrdHkiOiJSU0EiLCJuIjoiaFlPSi1YT0tJU2RNTV\ | ||||
Nobl9HNFc5bTIwbVQwVld0UUJzbUJCa0kyY21SdDRBaThCZllkSHNGekF0WUtPanB\ | ||||
CUjFScEtwSm1WS3hJR055MGc2WjNhZDJYWXNoOEtvd2x5Vnk4SWtaOE5Nd1NyY1VJ\ | ||||
QlpHWVhqSHB3anp2Zkd2WEhfNUtKbG5SM191UlVwNFo0VWprMmJDYUtlZ0RuMTFWM\ | ||||
nZ4RTQxaHFhUFVuaFJaeGUwalJFVGRkenNFM211MVNLOGRUQ1JPandVbDE0bVVObz\ | ||||
hpVHJUbTRuMHFEYWR6OEJrUG8tdXY0QkMwYnVuUzBLM2JBXzNVZ1ZwN3pCbFFGb0Z\ | ||||
uTFRPMnVXcF9tdUxFV0dsNjdnQnE5TU8zYnJLWGZHaGkza096eXd6d1BUdXEtY1ZR\ | ||||
RHlFTjdhTDBTeENiM0hjNElkcURhTWc4cUhVeU9icFBpdERRIn0sInR5cCI6ImRwb\ | ||||
3Arand0In0.eyJodHUiOiJodHRwczovL3NlcnZlci5leGFtcGxlLmNvbS9nbmFwIi\ | ||||
wiaHRtIjoiUE9TVCIsImlhdCI6MTYxODg4NDQ3NSwianRpIjoiSGpvSHJqZ20yeUI\ | ||||
0eDdqQTV5eUciLCJodGQiOiJTSEEtMjU2PXRuUFEyR1htOHIvclRUS2RiUThwYzdF\ | ||||
amlGRlB5MUV4U1g2T1pWRzNKVkk9In0.HLRh7n-3uwnSGCBGbSFitNCxgmJnpp6hs\ | ||||
sF8o_u2Xbuzu3pyR4v8SJVP17tjqxuySf91lmC1gjJeK4pXvWOtfeWGuDjD7nr6aw\ | ||||
pBOtiQXeBtoqiiK2ByBZO-mhccJeNkTkRfxGDtU0iJo6iarWjRgQOsPbt69FIwTP4\ | ||||
Abovwv7yBCthQs3TMsBtb8-l4Lu30wNLwXEWcB-o8nFNpT4zgV9ETGoCOcBFwBjjt\ | ||||
0khsCarleTBsOZ2zUuFwZMWi_bQYfd-M0pahWYro9Mdy3Fts-aUqZjS2LwHHNWvjw\ | ||||
rTzz6icCHwnr9dm1Ls6orbM7xMzvHAOA5TZW39yFg_Xr5PNYg | ||||
{ | kid (string) The key identifier. RECOMMENDED. If the key is | |||
"access_token": { | presented in JWK format, this MUST be the value of the "kid" field | |||
"access": [ | of the key. | |||
"dolphin-metadata" | ||||
] | ||||
}, | ||||
"interact": { | ||||
"start": ["redirect"], | ||||
"finish": { | ||||
"method": "redirect", | ||||
"uri": "https://client.foo/callback", | ||||
"nonce": "VJLO6A4CAYLBXHTR0KRO" | ||||
} | ||||
}, | ||||
"client": { | ||||
"proof": "dpop", | ||||
"key": { | ||||
"jwk": { | ||||
"kid": "gnap-rsa", | ||||
"kty": "RSA", | ||||
"e": "AQAB", | ||||
"alg": "RS256", | ||||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | ||||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | ||||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | ||||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ||||
3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | ||||
N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | ||||
} | ||||
} | ||||
"display": { | ||||
"name": "My Client Display Name", | ||||
"uri": "https://client.foo/" | ||||
}, | ||||
} | ||||
} | ||||
The verifier MUST parse and validate the DPoP proof header as defined | alg (string) The algorithm used to sign the request. REQUIRED. | |||
in [I-D.ietf-oauth-dpop]. If the HTTP message request includes a | MUST be appropriate to the key presented. If the key is presented | |||
message body, the verifier MUST calculate the digest of the body and | as a JWK, this MUST be equal to the "alg" parameter of the key. | |||
compare it to the "htd" value. The verifier MUST ensure the key | MUST NOT be "none". | |||
presented in the DPoP proof header is the same as the expected key of | ||||
the signer. | ||||
7.3.5. HTTP Message Signing | typ (string) The type header, value "gnap-binding+jwsd". REQUIRED | |||
This method is indicated by "httpsig" in the "proof" field. The | htm (string) The HTTP Method used to make this request, as an | |||
sender creates an HTTP Message Signature as described in | uppercase ASCII string. REQUIRED | |||
[I-D.ietf-httpbis-message-signatures]. | ||||
The covered content of the signature MUST include the following: | uri (string) The HTTP URI used for this request, including all path | |||
and query components and no fragment component. REQUIRED | ||||
@request-target: the target of the HTTP request | created (integer) A timestamp of when the signature was created, in | |||
integer seconds since UNIX Epoch | ||||
digest: The Digest header as defined in [RFC3230]. When the request | ath (string) When a request is bound to an access token, the access | |||
message has a body, the signer MUST calculate this header value | token hash value. The value MUST be the result of Base64url | |||
and the verifier MUST validate this header. | encoding (with no padding) the SHA-256 digest of the ASCII | |||
encoding of the associated access token's value. REQUIRED if the | ||||
request protects an access token. | ||||
When the request is bound to an access token, the covered content | If the HTTP request has a message body, such as an HTTP POST or PUT | |||
MUST also include: | method, the payload of the JWS object is the Base64url encoding | |||
(without padding) of the SHA256 digest of the bytes of the body. If | ||||
the request being made does not have a message body, such as an HTTP | ||||
GET, OPTIONS, or DELETE method, the JWS signature is calculated over | ||||
an empty payload. | ||||
authorization: The Authorization header used to present the access | The client instance presents the signed object in compact form | |||
token as discussed in Section 7.2. | [RFC7515] in the Detached-JWS HTTP Header field. | |||
Other covered content MAY also be included. | In this example, the JOSE Header contains the following parameters: | |||
If the signer's key presented is a JWK, the "keyid" parameter of the | { | |||
signature MUST be set to the "kid" value of the JWK, the signing | "alg": "RS256", | |||
algorithm used MUST be the JWS algorithm denoted by the key's "alg" | "kid": "gnap-rsa", | |||
field, and the explicit "alg" signature parameter MUST NOT be | "uri": "https://server.example.com/gnap", | |||
included. | "htm": "POST", | |||
"typ": "gnap-binding+jwsd", | ||||
"created": 1618884475 | ||||
} | ||||
In this example, the message body is the following JSON object: | The request body is the following JSON object: | |||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"dolphin-metadata" | "dolphin-metadata" | |||
] | ] | |||
}, | }, | |||
"interact": { | "interact": { | |||
"start": ["redirect"], | "start": ["redirect"], | |||
"finish": { | "finish": { | |||
"method": "redirect", | "method": "redirect", | |||
"uri": "https://client.foo/callback", | "uri": "https://client.foo/callback", | |||
"nonce": "VJLO6A4CAYLBXHTR0KRO" | "nonce": "VJLO6A4CAYLBXHTR0KRO" | |||
} | } | |||
}, | }, | |||
"client": { | "client": { | |||
"proof": "httpsig", | "proof": "jwsd", | |||
"key": { | "key": { | |||
"jwk": { | "jwk": { | |||
"kid": "gnap-rsa", | "kid": "gnap-rsa", | |||
"kty": "RSA", | "kty": "RSA", | |||
"e": "AQAB", | "e": "AQAB", | |||
"alg": "RS256", | "alg": "RS256", | |||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | "n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | |||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | |||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | |||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | |||
3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | 3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | |||
N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | |||
} | } | |||
} | } | |||
"display": { | "display": { | |||
"name": "My Client Display Name", | "name": "My Client Display Name", | |||
"uri": "https://client.foo/" | "uri": "https://client.foo/" | |||
}, | }, | |||
} | } | |||
} | } | |||
This body is hashed for the Digest header using SHA-256 into the | ||||
following encoded value: | ||||
SHA-256=98QzyNVYpdgTrWBKpC4qFSCmmR+CrwwvUoiaDCSjKxw= | This is hashed to the following Base64 encoded value: | |||
The HTTP message signature input string is calculated to be the | ||||
following: | ||||
"@request-target": post /gnap | PGiVuOZUcN1tRtUS6tx2b4cBgw9mPgXG3IPB3wY7ctc | |||
"host": server.example.com | ||||
"content-type": application/json | ||||
"digest": SHA-256=98QzyNVYpdgTrWBKpC4qFSCmmR+CrwwvUoiaDCSjKxw= | ||||
"content-length": 986 | ||||
"@signature-params": ("@request-target" "host" "content-type" \ | ||||
"digest" "content-length");created=1618884475;keyid="gnap-rsa" | ||||
This leads to the following full HTTP message request: | This leads to the following full HTTP request message: | |||
POST /gnap HTTP/1.1 | POST /gnap HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Content-Length: 986 | Content-Length: 983 | |||
Digest: SHA-256=98QzyNVYpdgTrWBKpC4qFSCmmR+CrwwvUoiaDCSjKxw= | Detached-JWS: eyJhbGciOiJSUzI1NiIsImNyZWF0ZWQiOjE2MTg4ODQ0NzUsImh0b\ | |||
Signature-Input: sig1=("@request-target" "host" "content-type" \ | SI6IlBPU1QiLCJraWQiOiJnbmFwLXJzYSIsInR5cCI6ImduYXAtYmluZGluZytqd3\ | |||
"digest" "content-length");created=1618884475;keyid="gnap-rsa" | NkIiwidXJpIjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20vZ25hcCJ9.PGiVuO\ | |||
Signature: \ | ZUcN1tRtUS6tx2b4cBgw9mPgXG3IPB3wY7ctc.fUq-SV-A1iFN2MwCRW_yolVtT2_\ | |||
sig1=:axj8FLOvEWBcwh+Xk6VTTKXxqo4XNygleTDJ8h3ZJfi1sSmWrRtyo9RG/dc\ | TZA2h5YeXUoi5F2Q2iToC0Tc4drYFOSHIX68knd68RUA7yHqCVP-ZQEd6aL32H69e\ | |||
miZmdszRjWbg+/ixVZpA4BL3AOwEOxxtmHAXNB8uJ0I3tfbs6Suyk4sEo8zPr+MJq\ | 9zuMiw6O_s4TBKB3vDOvwrhYtDH6fX2hP70cQoO-47OwbqP-ifkrvI3hVgMX9TfjV\ | |||
MjxdJEUgAQAy2AH+wg5a7CKq4IdLTulFK9njUIeG7MygHumeiumM3DbDQAHgF46dV\ | eKNwnhoNnw3vbu7SNKeqJEbbwZfpESaGepS52xNBlDNMYBQQXxM9OqKJaXffzLFEl\ | |||
q5UC6KJnqhGM1rFC128jd2D0sgWKCUgKGCHtfR159zfKWcEO9krsLoOnCdTzm1UyD\ | -Xe0UnfolVtBraz3aPrPy1C6a4uT7wLda3PaTOVtgysxzii3oJWpuz0WP5kRujzDF\ | |||
DMjkIjqeN/1j8PdMJaRAwV4On079O0DVu6bl1jVtkzo/e/ZmwPr/X436V4xiw/hZt\ | wX_EOzW0jsjCSkL-PXaKSpZgEjNjKDMg9irSxUISt1C1T6q3SzRgfuQ | |||
w4sfNsSbmsT0+UAQ20X/xaw==: | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"dolphin-metadata" | "dolphin-metadata" | |||
] | ] | |||
}, | }, | |||
"interact": { | "interact": { | |||
"start": ["redirect"], | "start": ["redirect"], | |||
"finish": { | "finish": { | |||
"method": "redirect", | "method": "redirect", | |||
"uri": "https://client.foo/callback", | "uri": "https://client.foo/callback", | |||
"nonce": "VJLO6A4CAYLBXHTR0KRO" | "nonce": "VJLO6A4CAYLBXHTR0KRO" | |||
} | } | |||
}, | }, | |||
"client": { | "client": { | |||
"proof": "httpsig", | "proof": "jwsd", | |||
"key": { | "key": { | |||
"jwk": { | "jwk": { | |||
"kid": "gnap-rsa", | "kid": "gnap-rsa", | |||
"kty": "RSA", | "kty": "RSA", | |||
"e": "AQAB", | "e": "AQAB", | |||
"alg": "RS256", | "alg": "RS256", | |||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | "n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | |||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | |||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | |||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | |||
skipping to change at page 99, line 23 ¶ | skipping to change at page 93, line 4 ¶ | |||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | |||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | |||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | |||
3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | 3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | |||
N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | |||
} | } | |||
} | } | |||
"display": { | "display": { | |||
"name": "My Client Display Name", | "name": "My Client Display Name", | |||
"uri": "https://client.foo/" | "uri": "https://client.foo/" | |||
}, | }, | |||
} | } | |||
} | } | |||
If the HTTP Message includes a message body, the verifier MUST | When the verifier receives the Detached-JWS header, it MUST parse and | |||
calculate and verify the value of the "Digest" header. The verifier | validate the JWS object. The signature MUST be validated against the | |||
MUST ensure that the signature includes all required covered content. | expected key of the signer. All required fields MUST be present and | |||
The verifier MUST validate the signature against the expected key of | their values MUST be valid. If the HTTP message request contains a | |||
the signer. | body, the verifier MUST calculate the hash of body just as the signer | |||
does, with no normalization or transformation of the request. | ||||
7.3.6. OAuth Proof of Possession (PoP) | 7.3.4. Attached JWS | |||
This method is indicated by "oauthpop" in the "proof" field. The | This method is indicated by "jws" in the "proof" field. A JWS | |||
signer creates an HTTP Authorization PoP header as described in | [RFC7515] object is created as follows: | |||
[I-D.ietf-oauth-signed-http-request] section 4, with the following | ||||
additional requirements: | ||||
* The "at" (access token) field MUST be omitted unless this method | The JOSE header MUST contain the "kid" parameter of the key bound to | |||
is being used in conjunction with an access token as in | this client instance for this request. The "alg" parameter MUST be | |||
Section 7.2. [[ See issue #112 (https://github.com/ietf-wg-gnap/ | set to a value appropriate for the key identified by kid and MUST NOT | |||
gnap-core-protocol/issues/112) ]] | be "none". | |||
* The "b" (body hash) field MUST be calculated and included, if the | To protect the request, the JWS header MUST contain the following | |||
message includes an entity body (such as a PUT or PATCH request). | additional parameters. | |||
* All components of the URL MUST be calculated and included, | typ (string) The type header, value "gnap-binding+jws". | |||
including query parameters "q", path "p", and host "u". | ||||
* The "m" (method) field MUST be included | htm (string) The HTTP Method used to make this request, as an | |||
In this example, the request message body is the following JSON | uppercase ASCII string. | |||
object | ||||
{ | uri (string) The HTTP URI used for this request, including all path | |||
"access_token": { | and query components and no fragment component. | |||
"access": [ | ||||
"dolphin-metadata" | ||||
] | ||||
}, | ||||
"interact": { | ||||
"start": ["redirect"], | ||||
"finish": { | ||||
"method": "redirect", | ||||
"uri": "https://client.foo/callback", | ||||
"nonce": "VJLO6A4CAYLBXHTR0KRO" | ||||
} | ||||
}, | ||||
"client": { | ||||
"proof": "oauthpop", | ||||
"key": { | ||||
"jwk": { | ||||
"kid": "gnap-rsa", | ||||
"kty": "RSA", | ||||
"e": "AQAB", | ||||
"alg": "RS256", | ||||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | ||||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | ||||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | ||||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ||||
3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | ||||
N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | ||||
} | ||||
} | ||||
"display": { | ||||
"name": "My Client Display Name", | ||||
"uri": "https://client.foo/" | ||||
}, | ||||
} | ||||
} | ||||
The JOSE header for the PoP token is the following: | created (integer) A timestamp of when the signature was created, in | |||
integer seconds since UNIX Epoch | ||||
{ | ath (string) When a request is bound to an access token, the access | |||
"alg": "RS256", | token hash value. The value MUST be the result of Base64url | |||
"kid": "gnap-rsa" | encoding (with no padding) the SHA-256 digest of the ASCII | |||
} | encoding of the associated access token's value. | |||
After calculating the hashes for the body, headers, and URL | ||||
components, the JWS Payload is the following: | If the HTTP request has a message body, such as an HTTP POST or PUT | |||
method, the payload of the JWS object is the JSON serialized body of | ||||
the request, and the object is signed according to JWS and serialized | ||||
into compact form [RFC7515]. The client instance presents the JWS as | ||||
the body of the request along with a content type of "application/ | ||||
jose". The AS MUST extract the payload of the JWS and treat it as | ||||
the request body for further processing. | ||||
If the request being made does not have a message body, such as an | ||||
HTTP GET, OPTIONS, or DELETE method, the JWS signature is calculated | ||||
over an empty payload and passed in the "Detached-JWS" header as | ||||
described in Section 7.3.3. | ||||
In this example, the JOSE header contains the following parameters: | ||||
{ | { | |||
"u": "server.example.com", | "alg": "RS256", | |||
"p": "/gnap", | "kid": "gnap-rsa", | |||
"m": "POST", | "uri": "https://server.example.com/gnap", | |||
"ts": 1618884475, | "htm": "POST", | |||
"b": "sCvbP9VqOcq4LHkVDcayon2MoT4xPGc49TEnqsr6WYE", | "typ": "gnap-binding+jwsd", | |||
"h": [ | "created": 1618884475 | |||
[ | ||||
"content-type", | ||||
"content-length" | ||||
], | ||||
"EJit2-669uk8JUzLJbidMFRkATuZOimvCOieXPjtEmU" | ||||
] | ||||
} | } | |||
This leads to the following HTTP message request: | The request body, used as the JWS Payload, is the following JSON | |||
object: | ||||
POST /gnap HTTP/1.1 | ||||
Host: server.example.com | ||||
Content-Type: application/json | ||||
Content-Length: 987 | ||||
PoP: eyJhbGciOiJSUzI1NiIsImtpZCI6ImduYXAtcnNhIn0.eyJ1Ijoic2VydmVyLm\ | ||||
V4YW1wbGUuY29tIiwicCI6Ii9nbmFwIiwibSI6IlBPU1QiLCJ0cyI6MTYxODg4NDQ\ | ||||
3NSwiYiI6InNDdmJQOVZxT2NxNExIa1ZEY2F5b24yTW9UNHhQR2M0OVRFbnFzcjZX\ | ||||
WUUiLCJoIjpbWyJjb250ZW50LXR5cGUiLCJjb250ZW50LWxlbmd0aCJdLCJFSml0M\ | ||||
i02Njl1azhKVXpMSmJpZE1GUmtBVHVaT2ltdkNPaWVYUGp0RW1VIl19.doLbW-VA7\ | ||||
HnyeyEbl4qmcPUkiQrXIG53oSZLGrUHhs7CL9X9kd_-1j8lxyT7tWJLtjoIgDtVVn\ | ||||
PN69xP-Vs9-Cx5uV4VfLKRO7O9GmdGUOXx9eP53Q4hf8UPMrfbyAEeluznajC21o9\ | ||||
AriBDMyjmV4A4JkZn3A7v72zE0z1CQfqUsdfomeB_SmFlMhcsO8KsT1vG6iOmuE0x\ | ||||
3rGjJvyohNUQvkzWvaP37nLTZol8VFWinlXGv-4cOx3YWgZUn_RNk7cH6ALHlzgnl\ | ||||
8t1YhA14AFdVmCGaeJMDKmb5Jt7g0UnOp1BYR9j1DeUP64RQU6lH_8A1MMIc5iBwD\ | ||||
yx433wxQ | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"dolphin-metadata" | "dolphin-metadata" | |||
] | ] | |||
}, | }, | |||
"interact": { | "interact": { | |||
"start": ["redirect"], | "start": ["redirect"], | |||
"finish": { | "finish": { | |||
"method": "redirect", | "method": "redirect", | |||
"uri": "https://client.foo/callback", | "uri": "https://client.foo/callback", | |||
"nonce": "VJLO6A4CAYLBXHTR0KRO" | "nonce": "VJLO6A4CAYLBXHTR0KRO" | |||
} | } | |||
}, | }, | |||
"client": { | "client": { | |||
"proof": "oauthpop", | "proof": "jws", | |||
"key": { | "key": { | |||
"jwk": { | "jwk": { | |||
"kid": "gnap-rsa", | "kid": "gnap-rsa", | |||
"kty": "RSA", | "kty": "RSA", | |||
"e": "AQAB", | "e": "AQAB", | |||
"alg": "RS256", | "alg": "RS256", | |||
"n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | "n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ | |||
YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ | |||
YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ | |||
ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ | |||
3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | 3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ | |||
N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" | |||
} | } | |||
} | } | |||
"display": { | "display": { | |||
"name": "My Client Display Name", | "name": "My Client Display Name", | |||
"uri": "https://client.foo/" | "uri": "https://client.foo/" | |||
}, | }, | |||
}, | ||||
"subject": { | ||||
"formats": ["iss_sub", "opaque"] | ||||
} | } | |||
} | } | |||
[[ See issue #113 (https://github.com/ietf-wg-gnap/gnap-core- | This leads to the following full HTTP request message: | |||
protocol/issues/113) ]] | ||||
The verifier MUST parse the JWS object of the PoP header. The | POST /gnap HTTP/1.1 | |||
verifier MUST validate the signature of the header against the | Host: server.example.com | |||
expected key of the signer. The verifier MUST ensure that all | Content-Type: application/jose | |||
required parts of the message are covered by the signature. The | Content-Length: 1047 | |||
verifier MUST ensure that all components of the signature contain | ||||
correct values. | eyJhbGciOiJSUzI1NiIsImNyZWF0ZWQiOjE2MTg4ODQ0NzUsImh0bSI6IlBPU1QiLCJ\ | |||
raWQiOiJnbmFwLXJzYSIsInR5cCI6ImduYXAtYmluZGluZytqd3NkIiwidXJpIjoiaH\ | ||||
R0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20vZ25hcCJ9.CnsKICAgICJhY2Nlc3NfdG9r\ | ||||
ZW4iOiB7CiAgICAgICAgImFjY2VzcyI6IFsKICAgICAgICAgICAgImRvbHBoaW4tbWV\ | ||||
0YWRhdGEiCiAgICAgICAgXQogICAgfSwKICAgICJpbnRlcmFjdCI6IHsKICAgICAgIC\ | ||||
Aic3RhcnQiOiBbInJlZGlyZWN0Il0sCiAgICAgICAgImZpbmlzaCI6IHsKICAgICAgI\ | ||||
CAgICAgIm1ldGhvZCI6ICJyZWRpcmVjdCIsCiAgICAgICAgICAgICJ1cmkiOiAiaHR0\ | ||||
cHM6Ly9jbGllbnQuZm9vL2NhbGxiYWNrIiwKICAgICAgICAgICAgIm5vbmNlIjogIlZ\ | ||||
KTE82QTRDQVlMQlhIVFIwS1JPIgogICAgICAgIH0KICAgIH0sCiAgICAiY2xpZW50Ij\ | ||||
ogewogICAgICAicHJvb2YiOiAiandzIiwKICAgICAgImtleSI6IHsKICAgICAgICAia\ | ||||
ndrIjogewogICAgICAgICAgICAia2lkIjogImduYXAtcnNhIiwKICAgICAgICAgICAg\ | ||||
Imt0eSI6ICJSU0EiLAogICAgICAgICAgICAiZSI6ICJBUUFCIiwKICAgICAgICAgICA\ | ||||
gImFsZyI6ICJSUzI1NiIsCiAgICAgICAgICAgICJuIjogImhZT0otWE9LSVNkTU1TaG\ | ||||
5fRzRXOW0yMG1UMFZXdFFCc21CQmtJMmNtUnQ0QWk4QmZZZEhzRnpBdFlLT2pwQlIxU\ | ||||
nBLcEptVkt4SUdOeTBnNlozYWQyWFlzaDhLb3dseVZ5OElrWjhOTXdTcmNVSUJaR1lY\ | ||||
akhwd2p6dmZHdlhIXzVLSmxuUjNfdVJVcDRaNFVqazJiQ2FLZWdEbjExVjJ2eEU0MWh\ | ||||
xYVBVbmhSWnhlMGpSRVRkZHpzRTNtdTFTSzhkVENST2p3VWwxNG1VTm84aVRyVG00bj\ | ||||
BxRGFkejhCa1BvLXV2NEJDMGJ1blMwSzNiQV8zVWdWcDd6QmxRRm9GbkxUTzJ1V3Bfb\ | ||||
XVMRVdHbDY3Z0JxOU1PM2JyS1hmR2hpM2tPenl3endQVHVxLWNWUUR5RU43YUwwU3hD\ | ||||
YjNIYzRJZHFEYU1nOHFIVXlPYnBQaXREUSIKICAgICAgICB9CiAgICAgIH0KICAgICA\ | ||||
gImRpc3BsYXkiOiB7CiAgICAgICAgIm5hbWUiOiAiTXkgQ2xpZW50IERpc3BsYXkgTm\ | ||||
FtZSIsCiAgICAgICAgInVyaSI6ICJodHRwczovL2NsaWVudC5mb28vIgogICAgICB9L\ | ||||
AogICAgfSwKICAgICJzdWJqZWN0IjogewogICAgICAgICJmb3JtYXRzIjogWyJpc3Nf\ | ||||
c3ViIiwgIm9wYXF1ZSJdCiAgICB9Cn0K.MwNoVMQp5hVxI0mCs9LlOUdFtkDXaA1_eT\ | ||||
vOXq7DOGrtDKH7q4vP2xUq3fH2jRAZqnobo0WdPP3eM3NH5QUjW8pa6_QpwdIWkK7r-\ | ||||
u_52puE0lPBp7J4U2w4l9gIbg8iknsmWmXeY5F6wiGT8ptfuEYGgmloAJd9LIeNvD3U\ | ||||
LW2h2dz1Pn2eDnbyvgB0Ugae0BoZB4f69fKWj8Z9wvTIjk1LZJN1PcL7_zT8Lrlic9a\ | ||||
PyzT7Q9ovkd1s-4whE7TrnGUzFc5mgWUn_gsOpsP5mIIljoEEv-FqOW2RyNYulOZl0Q\ | ||||
8EnnDHV_vPzrHlUarbGg4YffgtwkQhdK72-JOxYQ | ||||
[[ See issue #109 (https://github.com/ietf-wg-gnap/gnap-core- | ||||
protocol/issues/109) ]] | ||||
When the verifier receives an attached JWS request, it MUST parse and | ||||
validate the JWS object. The signature MUST be validated against the | ||||
expected key of the signer. All required fields MUST be present and | ||||
their values MUST be valid. If the HTTP message request contains a | ||||
body, the verifier MUST decode the payload of the JWS object and | ||||
treat this as the HTTP message body. | ||||
8. Resource Access Rights | 8. Resource Access Rights | |||
GNAP provides a rich structure for describing the protected resources | GNAP provides a rich structure for describing the protected resources | |||
hosted by RSs and accessed by client software. This structure is | hosted by RSs and accessed by client software. This structure is | |||
used when the client instance requests an access token (Section 2.1) | used when the client instance requests an access token (Section 2.1) | |||
and when an access token is returned (Section 3.2). | and when an access token is returned (Section 3.2). | |||
The root of this structure is a JSON array. The elements of the JSON | The root of this structure is a JSON array. The elements of the JSON | |||
array represent rights of access that are associated with the the | array represent rights of access that are associated with the the | |||
skipping to change at page 103, line 46 ¶ | skipping to change at page 98, line 9 ¶ | |||
datatypes (array of strings) The kinds of data available to the | datatypes (array of strings) The kinds of data available to the | |||
client instance at the RS's API as an array of strings. For | client instance at the RS's API as an array of strings. For | |||
example, a client instance asking for access to raw "image" data | example, a client instance asking for access to raw "image" data | |||
and "metadata" at a photograph API. | and "metadata" at a photograph API. | |||
identifier (string) A string identifier indicating a specific | identifier (string) A string identifier indicating a specific | |||
resource at the RS. For example, a patient identifier for a | resource at the RS. For example, a patient identifier for a | |||
medical API or a bank account number for a financial API. | medical API or a bank account number for a financial API. | |||
privileges (array of strings) The types or levels of privilege being | ||||
requested at the resource. For example, a client instance asking | ||||
for administrative level access, or access when the resource owner | ||||
is no longer online. | ||||
The following non-normative example is describing three kinds of | The following non-normative example is describing three kinds of | |||
access (read, write, delete) to each of two different locations and | access (read, write, delete) to each of two different locations and | |||
two different data types (metadata, images) for a single access token | two different data types (metadata, images) for a single access token | |||
using the fictitious "photo-api" type definition. | using the fictitious "photo-api" type definition. | |||
"access": [ | "access": [ | |||
{ | { | |||
"type": "photo-api", | "type": "photo-api", | |||
"actions": [ | "actions": [ | |||
"read", | "read", | |||
skipping to change at page 109, line 10 ¶ | skipping to change at page 103, line 10 ¶ | |||
endpoint to retrieve the server's discovery information. The AS MUST | endpoint to retrieve the server's discovery information. The AS MUST | |||
respond with a JSON document containing the following information: | respond with a JSON document containing the following information: | |||
grant_request_endpoint (string) REQUIRED. The location of the AS's | grant_request_endpoint (string) REQUIRED. The location of the AS's | |||
grant request endpoint. The location MUST be a URL [RFC3986] with | grant request endpoint. The location MUST be a URL [RFC3986] with | |||
a scheme component that MUST be https, a host component, and | a scheme component that MUST be https, a host component, and | |||
optionally, port, path and query components and no fragment | optionally, port, path and query components and no fragment | |||
components. This URL MUST match the URL the client instance used | components. This URL MUST match the URL the client instance used | |||
to make the discovery request. | to make the discovery request. | |||
capabilities (array of strings) OPTIONAL. A list of the AS's | interaction_start_modes_supported (array of strings) OPTIONAL. A | |||
capabilities. The values of this result MAY be used by the client | list of the AS's interaction start methods. The values of this | |||
instance in the capabilities section (Section 2.6) of the request. | list correspond to the possible values for the interaction start | |||
section (Section 2.5.1) of the request. | ||||
interaction_methods_supported (array of strings) OPTIONAL. A list | interaction_finish_methods_supported (array of strings) OPTIONAL. A | |||
of the AS's interaction methods. The values of this list | list of the AS's interaction finish methods. The values of this | |||
correspond to the possible fields in the interaction section | list correspond to the possible values for the method element of | |||
(Section 2.5) of the request. | the interaction finish section (Section 2.5.2) of the request. | |||
key_proofs_supported (array of strings) OPTIONAL. A list of the | key_proofs_supported (array of strings) OPTIONAL. A list of the | |||
AS's supported key proofing mechanisms. The values of this list | AS's supported key proofing mechanisms. The values of this list | |||
correspond to possible values of the "proof" field of the key | correspond to possible values of the "proof" field of the key | |||
section (Section 7.1) of the request. | section (Section 7.1) of the request. | |||
subject_formats_supported (array of strings) OPTIONAL. A list of | subject_formats_supported (array of strings) OPTIONAL. A list of | |||
the AS's supported subject identifier types. The values of this | the AS's supported subject identifier types. The values of this | |||
list correspond to possible values of the subject identifier | list correspond to possible values of the subject identifier | |||
section (Section 2.2) of the request. | section (Section 2.2) of the request. | |||
skipping to change at page 109, line 42 ¶ | skipping to change at page 103, line 43 ¶ | |||
(Section 2.2) of the request. | (Section 2.2) of the request. | |||
The information returned from this method is for optimization | The information returned from this method is for optimization | |||
purposes only. The AS MAY deny any request, or any portion of a | purposes only. The AS MAY deny any request, or any portion of a | |||
request, even if it lists a capability as supported. For example, a | request, even if it lists a capability as supported. For example, a | |||
given client instance can be registered with the "mtls" key proofing | given client instance can be registered with the "mtls" key proofing | |||
mechanism, but the AS also returns other proofing methods, then the | mechanism, but the AS also returns other proofing methods, then the | |||
AS will deny a request from that client instance using a different | AS will deny a request from that client instance using a different | |||
proofing mechanism. | proofing mechanism. | |||
9.1. RS-first Method of AS Discovery | ||||
If the client instance calls an RS without an access token, or with | ||||
an invalid access token, the RS MAY respond to the client instance | ||||
with an authentication header indicating that GNAP needs to be used | ||||
to access the resource. The address of the GNAP endpoint MUST be | ||||
sent in the "as_uri" parameter. The RS MAY additionally return a | ||||
resource reference that the client instance MAY use in its access | ||||
token request. This resource reference MUST be sufficient for at | ||||
least the action the client instance was attempting to take at the RS | ||||
and MAY be more powerful. The means for the RS to determine the | ||||
resource reference are out of scope of this specification, but some | ||||
dynamic methods are discussed in | ||||
[I-D.draft-ietf-gnap-resource-servers]. The content of the resource | ||||
handle is opaque to the client instance. | ||||
WWW-Authenticate: \ | ||||
GNAP as_uri=https://server.example/tx,access=FWWIKYBQ6U56NL1 | ||||
The client instance then makes a request to the "as_uri" as described | ||||
in Section 2, with the value of "access" as one of the members of the | ||||
"access" array in the "access_token" portion of the request. The | ||||
client instance MAY request additional resources and other | ||||
information. The client instance MAY request multiple access tokens. | ||||
In this non-normative example, the client instance is requesting a | ||||
single access token using the resource reference "FWWIKYBQ6U56NL1" | ||||
received from the RS in addition to the "dolphin-metadata" resource | ||||
reference that the client instance has been configured with out of | ||||
band. | ||||
POST /tx HTTP/1.1 | ||||
Host: server.example.com | ||||
Content-Type: application/json | ||||
Signature-Input: sig1=... | ||||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | ||||
"access_token": { | ||||
"access": [ | ||||
"FWWIKYBQ6U56NL1", | ||||
"dolphin-metadata" | ||||
] | ||||
}, | ||||
"client": "KHRS6X63AJ7C7C4AZ9AO" | ||||
} | ||||
If issued, the resulting access token would contain sufficient access | ||||
to be used at both referenced resources. | ||||
10. Acknowledgements | 10. Acknowledgements | |||
The editors would like to thank the feedback of the following | The editors would like to thank the feedback of the following | |||
individuals for their reviews, implementations, and contributions: | individuals for their reviews, implementations, and contributions: | |||
Aaron Parecki, Annabelle Backman, Dick Hardt, Dmitri Zagidulin, | Aeke Axeland, Aaron Parecki, Adam Omar Oueidat, Annabelle Backman, | |||
Dmitry Barinov, Fabien Imbault, Francis Pouatcha, George Fletcher, | Dick Hardt, Dmitri Zagidulin, Dmitry Barinov, Fabien Imbault, Francis | |||
Haardik Haardik, Hamid Massaoud, Jacky Yuan, Joseph Heenan, Justin | Pouatcha, George Fletcher, Haardik Haardik, Hamid Massaoud, Jacky | |||
Richer, Kathleen Moriarty, Mike Jones, Mike Varley, Nat Sakimura, | Yuan, Joseph Heenan, Justin Richer, Kathleen Moriarty, Mike Jones, | |||
Takahiko Kawasaki, Takahiro Tsuchiya. | Mike Varley, Nat Sakimura, Takahiko Kawasaki, Takahiro Tsuchiya. | |||
The editors would also like to thank the GNAP working group design | The editors would also like to thank the GNAP working group design | |||
team of Kathleen Moriarty, Fabien Imbault, Dick Hardt, Mike Jones, | team of Kathleen Moriarty, Fabien Imbault, Dick Hardt, Mike Jones, | |||
and Justin Richer, who incorporated elements from the XAuth and XYZ | and Justin Richer, who incorporated elements from the XAuth and XYZ | |||
proposals to create the first version of this document. | proposals to create the first version of this document. | |||
In addition, the editors would like to thank Aaron Parecki and Mike | In addition, the editors would like to thank Aaron Parecki and Mike | |||
Jones for insights into how to integrate identity and authentication | Jones for insights into how to integrate identity and authentication | |||
systems into the core protocol, and Justin Richer and Dick Hardt for | systems into the core protocol, and Justin Richer and Dick Hardt for | |||
the use cases, diagrams, and insights provided in the XYZ and XAuth | the use cases, diagrams, and insights provided in the XYZ and XAuth | |||
skipping to change at page 110, line 51 ¶ | skipping to change at page 106, line 12 ¶ | |||
14. Normative References | 14. Normative References | |||
[BCP195] Sheffer, Y., Holz, R., and P. Saint-Andre, | [BCP195] Sheffer, Y., Holz, R., and P. Saint-Andre, | |||
"Recommendations for Secure Use of Transport Layer | "Recommendations for Secure Use of Transport Layer | |||
Security (TLS) and Datagram Transport Layer Security | Security (TLS) and Datagram Transport Layer Security | |||
(DTLS)", May 2015, | (DTLS)", May 2015, | |||
<https://www.rfc-editor.org/info/bcp195>. | <https://www.rfc-editor.org/info/bcp195>. | |||
[I-D.draft-ietf-gnap-resource-servers] | [I-D.draft-ietf-gnap-resource-servers] | |||
"*** BROKEN REFERENCE ***". | Richer, J., Parecki, A., and F. Imbault, "Grant | |||
Negotiation and Authorization Protocol Resource Server | ||||
Connections", Work in Progress, Internet-Draft, draft- | ||||
ietf-gnap-resource-servers-00, 28 April 2021, | ||||
<https://www.ietf.org/archive/id/draft-ietf-gnap-resource- | ||||
servers-00.txt>. | ||||
[I-D.ietf-httpbis-message-signatures] | [I-D.ietf-httpbis-message-signatures] | |||
Backman, A., Richer, J., and M. Sporny, "Signing HTTP | Backman, A., Richer, J., and M. Sporny, "Signing HTTP | |||
Messages", Work in Progress, Internet-Draft, draft-ietf- | Messages", Work in Progress, Internet-Draft, draft-ietf- | |||
httpbis-message-signatures-04, 21 April 2021, | httpbis-message-signatures-05, 8 June 2021, | |||
<https://www.ietf.org/archive/id/draft-ietf-httpbis- | <https://www.ietf.org/archive/id/draft-ietf-httpbis- | |||
message-signatures-04.txt>. | message-signatures-05.txt>. | |||
[I-D.ietf-oauth-dpop] | ||||
Fett, D., Campbell, B., Bradley, J., Lodderstedt, T., | ||||
Jones, M., and D. Waite, "OAuth 2.0 Demonstrating Proof- | ||||
of-Possession at the Application Layer (DPoP)", Work in | ||||
Progress, Internet-Draft, draft-ietf-oauth-dpop-03, 7 | ||||
April 2021, <https://www.ietf.org/archive/id/draft-ietf- | ||||
oauth-dpop-03.txt>. | ||||
[I-D.ietf-oauth-rar] | [I-D.ietf-oauth-rar] | |||
Lodderstedt, T., Richer, J., and B. Campbell, "OAuth 2.0 | Lodderstedt, T., Richer, J., and B. Campbell, "OAuth 2.0 | |||
Rich Authorization Requests", Work in Progress, Internet- | Rich Authorization Requests", Work in Progress, Internet- | |||
Draft, draft-ietf-oauth-rar-04, 7 February 2021, | Draft, draft-ietf-oauth-rar-05, 15 May 2021, | |||
<https://www.ietf.org/archive/id/draft-ietf-oauth-rar- | <https://www.ietf.org/archive/id/draft-ietf-oauth-rar- | |||
04.txt>. | 05.txt>. | |||
[I-D.ietf-oauth-signed-http-request] | [I-D.ietf-oauth-signed-http-request] | |||
Richer, J., Bradley, J., and H. Tschofenig, "A Method for | Richer, J., Bradley, J., and H. Tschofenig, "A Method for | |||
Signing HTTP Requests for OAuth", Work in Progress, | Signing HTTP Requests for OAuth", Work in Progress, | |||
Internet-Draft, draft-ietf-oauth-signed-http-request-03, 8 | Internet-Draft, draft-ietf-oauth-signed-http-request-03, 8 | |||
August 2016, <https://www.ietf.org/archive/id/draft-ietf- | August 2016, <https://www.ietf.org/archive/id/draft-ietf- | |||
oauth-signed-http-request-03.txt>. | oauth-signed-http-request-03.txt>. | |||
[I-D.ietf-secevent-subject-identifiers] | [I-D.ietf-secevent-subject-identifiers] | |||
Backman, A. and M. Scurtescu, "Subject Identifiers for | Backman, A. and M. Scurtescu, "Subject Identifiers for | |||
Security Event Tokens", Work in Progress, Internet-Draft, | Security Event Tokens", Work in Progress, Internet-Draft, | |||
draft-ietf-secevent-subject-identifiers-07, 8 March 2021, | draft-ietf-secevent-subject-identifiers-08, 24 May 2021, | |||
<https://www.ietf.org/archive/id/draft-ietf-secevent- | <https://www.ietf.org/archive/id/draft-ietf-secevent- | |||
subject-identifiers-07.txt>. | subject-identifiers-08.txt>. | |||
[OIDC] Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and | [OIDC] Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and | |||
C. Mortimore, "OpenID Connect Core 1.0 incorporating | C. Mortimore, "OpenID Connect Core 1.0 incorporating | |||
errata set 1", November 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>. | |||
[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>. | |||
skipping to change at page 113, line 18 ¶ | skipping to change at page 108, line 23 ¶ | |||
DOI 10.17487/RFC8705, February 2020, | DOI 10.17487/RFC8705, February 2020, | |||
<https://www.rfc-editor.org/info/rfc8705>. | <https://www.rfc-editor.org/info/rfc8705>. | |||
[RFC8792] Watsen, K., Auerswald, E., Farrel, A., and Q. Wu, | [RFC8792] Watsen, K., Auerswald, E., Farrel, A., and Q. Wu, | |||
"Handling Long Lines in Content of Internet-Drafts and | "Handling Long Lines in Content of Internet-Drafts and | |||
RFCs", RFC 8792, DOI 10.17487/RFC8792, June 2020, | RFCs", RFC 8792, DOI 10.17487/RFC8792, June 2020, | |||
<https://www.rfc-editor.org/info/rfc8792>. | <https://www.rfc-editor.org/info/rfc8792>. | |||
Appendix A. Document History | Appendix A. Document History | |||
* -05 | * -06 | |||
- Removed "capabilities" and "existing_grant" protocol fields. | ||||
- Removed separate "instance_id" field. | ||||
- Split "interaction_methods_supported" into | ||||
"interaction_start_modes_supported" and | ||||
"interaction_finish_methods_supported". | ||||
- Added AS endpoint to hash calculation to fix mix-up attack. | ||||
- Added "privileges" field to resource access request object. | ||||
- Moved client-facing RS response back from GNAP-RS document. | ||||
- Removed oauthpop key binding. | ||||
- Removed dpop key binding. | ||||
- Added example DID identifier. | ||||
- Changed token response booleans to flag structure to match | ||||
request. | ||||
- Updated signature examples to use HTTP Message Signatures. | ||||
* -05 | ||||
- Changed "interaction_methods" to | - Changed "interaction_methods" to | |||
"interaction_methods_supported". | "interaction_methods_supported". | |||
- Changed "key_proofs" to "key_proofs_supported". | - Changed "key_proofs" to "key_proofs_supported". | |||
- Changed "assertions" to "assertions_supported". | - Changed "assertions" to "assertions_supported". | |||
- Updated discovery and field names for subject formats. | - Updated discovery and field names for subject formats. | |||
- Add an appendix to provide protocol rationale, compared to | - Add an appendix to provide protocol rationale, compared to | |||
skipping to change at page 119, line 8 ¶ | skipping to change at page 114, line 8 ¶ | |||
and the client instance can take front-channel callbacks on the same | and the client instance can take front-channel callbacks on the same | |||
device as the user. This combination is analogous to the OAuth 2.0 | device as the user. This combination is analogous to the OAuth 2.0 | |||
Authorization Code grant type. | Authorization Code grant type. | |||
The client instance initiates the request to the AS. Here the client | The client instance initiates the request to the AS. Here the client | |||
instance identifies itself using its public key. | instance identifies itself using its public key. | |||
POST /tx HTTP/1.1 | POST /tx HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
{ | { | |||
"actions": [ | "actions": [ | |||
"read", | "read", | |||
"write", | "write", | |||
"dolphin" | "dolphin" | |||
], | ], | |||
skipping to change at page 119, line 32 ¶ | skipping to change at page 114, line 34 ¶ | |||
], | ], | |||
"datatypes": [ | "datatypes": [ | |||
"metadata", | "metadata", | |||
"images" | "images" | |||
] | ] | |||
} | } | |||
], | ], | |||
}, | }, | |||
"client": { | "client": { | |||
"key": { | "key": { | |||
"proof": "jwsd", | "proof": "httpsig", | |||
"jwk": { | "jwk": { | |||
"kty": "RSA", | "kty": "RSA", | |||
"e": "AQAB", | "e": "AQAB", | |||
"kid": "xyz-1", | "kid": "xyz-1", | |||
"alg": "RS256", | "alg": "RS256", | |||
"n": "kOB5rR4Jv0GMeLaY6_It_r3ORwdf8ci_JtffXyaSx8..." | "n": "kOB5rR4Jv0GMeLaY6_It_r3ORwdf8ci_JtffXyaSx8..." | |||
} | } | |||
} | } | |||
}, | }, | |||
"interact": { | "interact": { | |||
skipping to change at page 121, line 13 ¶ | skipping to change at page 116, line 13 ¶ | |||
out by validating session information and retrieves the stored | out by validating session information and retrieves the stored | |||
pending request. The client instance uses the values in this to | pending request. The client instance uses the values in this to | |||
validate the hash parameter. The client instance then calls the | validate the hash parameter. The client instance then calls the | |||
continuation URL and presents the handle and interaction reference in | continuation URL and presents the handle and interaction reference in | |||
the request body. The client instance signs the request as above. | the request body. The client instance signs the request as above. | |||
POST /continue HTTP/1.1 | POST /continue HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"interact_ref": "4IFWWIKYBC2PQ6U56NL1" | "interact_ref": "4IFWWIKYBC2PQ6U56NL1" | |||
} | } | |||
The AS retrieves the pending request based on the handle and issues a | The AS retrieves the pending request based on the handle and issues a | |||
bearer access token and returns this to the client instance. | bearer access token and returns this to the client instance. | |||
HTTP/1.1 200 OK | HTTP/1.1 200 OK | |||
Content-Type: application/json | Content-Type: application/json | |||
skipping to change at page 123, line 8 ¶ | skipping to change at page 118, line 8 ¶ | |||
The client instance can display a user code or a printable QR code. | The client instance can display a user code or a printable QR code. | |||
The client instance is not able to accept callbacks from the AS and | The client instance is not able to accept callbacks from the AS and | |||
needs to poll for updates while waiting for the user to authorize the | needs to poll for updates while waiting for the user to authorize the | |||
request. | request. | |||
The client instance initiates the request to the AS. | The client instance initiates the request to the AS. | |||
POST /tx HTTP/1.1 | POST /tx HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"dolphin-metadata", "some other thing" | "dolphin-metadata", "some other thing" | |||
], | ], | |||
}, | }, | |||
"client": "7C7C4AZ9KHRS6X63AJAO", | "client": "7C7C4AZ9KHRS6X63AJAO", | |||
"interact": { | "interact": { | |||
"start": ["redirect", "user_code"] | "start": ["redirect", "user_code"] | |||
skipping to change at page 124, line 26 ¶ | skipping to change at page 119, line 26 ¶ | |||
the user a message to return to their device. | the user a message to return to their device. | |||
Meanwhile, the client instance periodically polls the AS every 60 | Meanwhile, the client instance periodically polls the AS every 60 | |||
seconds at the continuation URL. The client instance signs the | seconds at the continuation URL. The client instance signs the | |||
request using the same key and method that it did in the first | request using the same key and method that it did in the first | |||
request. | request. | |||
POST /continue/VGJKPTKC50 HTTP/1.1 | POST /continue/VGJKPTKC50 HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
The AS retrieves the pending request based on the handle and | The AS retrieves the pending request based on the handle and | |||
determines that it has not yet been authorized. The AS indicates to | determines that it has not yet been authorized. The AS indicates to | |||
the client instance that no access token has yet been issued but it | the client instance that no access token has yet been issued but it | |||
can continue to call after another 60 second timeout. | can continue to call after another 60 second timeout. | |||
HTTP/1.1 200 OK | HTTP/1.1 200 OK | |||
Content-Type: application/json | Content-Type: application/json | |||
Cache-Control: no-store | Cache-Control: no-store | |||
skipping to change at page 124, line 46 ¶ | skipping to change at page 120, line 4 ¶ | |||
{ | { | |||
"continue": { | "continue": { | |||
"access_token": { | "access_token": { | |||
"value": "G7YQT4KQQ5TZY9SLSS5E" | "value": "G7YQT4KQQ5TZY9SLSS5E" | |||
}, | }, | |||
"uri": "https://server.example.com/continue/ATWHO4Q1WV", | "uri": "https://server.example.com/continue/ATWHO4Q1WV", | |||
"wait": 60 | "wait": 60 | |||
} | } | |||
} | } | |||
Note that the continuation URL and access token have been rotated | Note that the continuation URL and access token have been rotated | |||
since they were used by the client instance to make this call. The | since they were used by the client instance to make this call. The | |||
client instance polls the continuation URL after a 60 second timeout | client instance polls the continuation URL after a 60 second timeout | |||
using this new information. | using this new information. | |||
POST /continue/ATWHO4Q1WV HTTP/1.1 | POST /continue/ATWHO4Q1WV HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Authorization: GNAP G7YQT4KQQ5TZY9SLSS5E | Authorization: GNAP G7YQT4KQQ5TZY9SLSS5E | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
The AS retrieves the pending request based on the URL and access | The AS retrieves the pending request based on the URL and access | |||
token, determines that it has been approved, and issues an access | token, determines that it has been approved, and issues an access | |||
token for the client to use at the RS. | token for the client to use at the RS. | |||
HTTP/1.1 200 OK | HTTP/1.1 200 OK | |||
Content-Type: application/json | Content-Type: application/json | |||
Cache-Control: no-store | Cache-Control: no-store | |||
{ | { | |||
skipping to change at page 127, line 8 ¶ | skipping to change at page 122, line 8 ¶ | |||
In this scenario, the client instance is requesting on behalf of a | In this scenario, the client instance is requesting on behalf of a | |||
specific RO, but has no way to interact with the user. The AS can | specific RO, but has no way to interact with the user. The AS can | |||
asynchronously reach out to the RO for approval in this scenario. | asynchronously reach out to the RO for approval in this scenario. | |||
The client instance starts the request at the AS by requesting a set | The client instance starts the request at the AS by requesting a set | |||
of resources. The client instance also identifies a particular user. | of resources. The client instance also identifies a particular user. | |||
POST /tx HTTP/1.1 | POST /tx HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
{ | { | |||
"type": "photo-api", | "type": "photo-api", | |||
"actions": [ | "actions": [ | |||
"read", | "read", | |||
"write", | "write", | |||
"dolphin" | "dolphin" | |||
skipping to change at page 128, line 34 ¶ | skipping to change at page 123, line 34 ¶ | |||
The AS reaches out to the RO and prompts them for consent. In this | The AS reaches out to the RO and prompts them for consent. In this | |||
example, the AS has an application that it can push notifications in | example, the AS has an application that it can push notifications in | |||
to for the specified account. | to for the specified account. | |||
Meanwhile, the client instance periodically polls the AS every 60 | Meanwhile, the client instance periodically polls the AS every 60 | |||
seconds at the continuation URL. | seconds at the continuation URL. | |||
POST /continue HTTP/1.1 | POST /continue HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Authorization: GNAP 80UPRY5NM33OMUKMKSKU | Authorization: GNAP 80UPRY5NM33OMUKMKSKU | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
The AS retrieves the pending request based on the handle and | The AS retrieves the pending request based on the handle and | |||
determines that it has not yet been authorized. The AS indicates to | determines that it has not yet been authorized. The AS indicates to | |||
the client instance that no access token has yet been issued but it | the client instance that no access token has yet been issued but it | |||
can continue to call after another 60 second timeout. | can continue to call after another 60 second timeout. | |||
HTTP/1.1 200 OK | HTTP/1.1 200 OK | |||
Content-Type: application/json | Content-Type: application/json | |||
Cache-Control: no-store | Cache-Control: no-store | |||
skipping to change at page 129, line 26 ¶ | skipping to change at page 124, line 26 ¶ | |||
} | } | |||
} | } | |||
Note that the continuation handle has been rotated since it was used | Note that the continuation handle has been rotated since it was used | |||
by the client instance to make this call. The client instance polls | by the client instance to make this call. The client instance polls | |||
the continuation URL after a 60 second timeout using the new handle. | the continuation URL after a 60 second timeout using the new handle. | |||
POST /continue HTTP/1.1 | POST /continue HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Authorization: GNAP BI9QNW6V9W3XFJK4R02D | Authorization: GNAP BI9QNW6V9W3XFJK4R02D | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
The AS retrieves the pending request based on the handle and | The AS retrieves the pending request based on the handle and | |||
determines that it has been approved and it issues an access token. | determines that it has been approved and it issues an access token. | |||
HTTP/1.1 200 OK | HTTP/1.1 200 OK | |||
Content-Type: application/json | Content-Type: application/json | |||
Cache-Control: no-store | Cache-Control: no-store | |||
{ | { | |||
"access_token": { | "access_token": { | |||
skipping to change at page 130, line 26 ¶ | skipping to change at page 125, line 26 ¶ | |||
&response_type=code | &response_type=code | |||
&state=123455 | &state=123455 | |||
Now the developer wants to make an analogous request to the AS using | Now the developer wants to make an analogous request to the AS using | |||
GNAP. To do so, the client instance makes an HTTP POST and places | GNAP. To do so, the client instance makes an HTTP POST and places | |||
the OAuth 2.0 values in the appropriate places. | the OAuth 2.0 values in the appropriate places. | |||
POST /tx HTTP/1.1 | POST /tx HTTP/1.1 | |||
Host: server.example.com | Host: server.example.com | |||
Content-Type: application/json | Content-Type: application/json | |||
Detached-JWS: ejy0... | Signature-Input: sig1=... | |||
Signature: sig1=... | ||||
Digest: sha256=... | ||||
{ | { | |||
"access_token": { | "access_token": { | |||
"access": [ | "access": [ | |||
"read", "write", "dolphin" | "read", "write", "dolphin" | |||
], | ], | |||
"flags": [ "bearer" ] | "flags": [ "bearer" ] | |||
}, | }, | |||
"client": "7C7C4AZ9KHRS6X63AJAO", | "client": "7C7C4AZ9KHRS6X63AJAO", | |||
"interact": { | "interact": { | |||
End of changes. 155 change blocks. | ||||
796 lines changed or deleted | 641 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |