--- 1/draft-ietf-gnap-core-protocol-05.txt 2021-07-12 09:13:29.262277298 -0700 +++ 2/draft-ietf-gnap-core-protocol-06.txt 2021-07-12 09:13:29.478282621 -0700 @@ -1,21 +1,21 @@ GNAP J. Richer, Ed. Internet-Draft Bespoke Engineering Intended status: Standards Track A. Parecki -Expires: 30 October 2021 Okta +Expires: 13 January 2022 Okta F. Imbault acert.io - 28 April 2021 + 12 July 2021 Grant Negotiation and Authorization Protocol - draft-ietf-gnap-core-protocol-05 + draft-ietf-gnap-core-protocol-06 Abstract GNAP defines a mechanism for delegating authorization to a piece of software, and conveying that delegation to the software. This delegation can include access to a set of APIs as well as information passed directly to the software. Status of This Memo @@ -25,146 +25,153 @@ Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference 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 (c) 2021 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/ license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License. Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 1.1. Terminology . . . . . . . . . . . . . . . . . . . . . . . 5 1.2. Roles . . . . . . . . . . . . . . . . . . . . . . . . . . 5 - 1.3. Elements . . . . . . . . . . . . . . . . . . . . . . . . 7 - 1.4. Sequences . . . . . . . . . . . . . . . . . . . . . . . . 8 - 1.4.1. Redirect-based Interaction . . . . . . . . . . . . . 11 - 1.4.2. User-code Interaction . . . . . . . . . . . . . . . . 14 - 1.4.3. Asynchronous Authorization . . . . . . . . . . . . . 16 - 1.4.4. Software-only Authorization . . . . . . . . . . . . . 18 - 1.4.5. Refreshing an Expired Access Token . . . . . . . . . 19 - 1.4.6. Requesting User Information . . . . . . . . . . . . . 21 - 2. Requesting Access . . . . . . . . . . . . . . . . . . . . . . 22 - 2.1. Requesting Access to Resources . . . . . . . . . . . . . 24 - 2.1.1. Requesting a Single Access Token . . . . . . . . . . 24 - 2.1.2. Requesting Multiple Access Tokens . . . . . . . . . . 27 - 2.2. Requesting Subject Information . . . . . . . . . . . . . 29 - 2.3. Identifying the Client Instance . . . . . . . . . . . . . 30 - 2.3.1. Identifying the Client Instance by Reference . . . . 31 - 2.3.2. Providing Displayable Client Instance Information . . 32 + 1.3. Elements . . . . . . . . . . . . . . . . . . . . . . . . 8 + 1.4. Sequences . . . . . . . . . . . . . . . . . . . . . . . . 9 + 1.4.1. Redirect-based Interaction . . . . . . . . . . . . . 12 + 1.4.2. User-code Interaction . . . . . . . . . . . . . . . . 15 + 1.4.3. Asynchronous Authorization . . . . . . . . . . . . . 17 + 1.4.4. Software-only Authorization . . . . . . . . . . . . . 19 + 1.4.5. Refreshing an Expired Access Token . . . . . . . . . 20 + 1.4.6. Requesting User Information . . . . . . . . . . . . . 22 + 2. Requesting Access . . . . . . . . . . . . . . . . . . . . . . 23 + 2.1. Requesting Access to Resources . . . . . . . . . . . . . 25 + 2.1.1. Requesting a Single Access Token . . . . . . . . . . 25 + 2.1.2. Requesting Multiple Access Tokens . . . . . . . . . . 28 + 2.2. Requesting Subject Information . . . . . . . . . . . . . 30 + 2.3. Identifying the Client Instance . . . . . . . . . . . . . 31 + 2.3.1. Identifying the Client Instance by Reference . . . . 32 + 2.3.2. Providing Displayable Client Instance Information . . 33 2.3.3. Authenticating the Client Instance . . . . . . . . . 33 - 2.4. Identifying the User . . . . . . . . . . . . . . . . . . 33 - 2.4.1. Identifying the User by Reference . . . . . . . . . . 34 + 2.4. Identifying the User . . . . . . . . . . . . . . . . . . 34 + 2.4.1. Identifying the User by Reference . . . . . . . . . . 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.3. Hints . . . . . . . . . . . . . . . . . . . . . . . . 40 + 2.5.3. Hints . . . . . . . . . . . . . . . . . . . . . . . . 41 2.5.4. Extending Interaction Modes . . . . . . . . . . . . . 41 - 2.6. Declaring Client Capabilities . . . . . . . . . . . . . . 41 - 2.7. Referencing an Existing Grant Request . . . . . . . . . . 41 - 2.8. Extending The Grant Request . . . . . . . . . . . . . . . 42 + 2.6. Extending The Grant Request . . . . . . . . . . . . . . . 41 3. Grant Response . . . . . . . . . . . . . . . . . . . . . . . 42 - 3.1. Request Continuation . . . . . . . . . . . . . . . . . . 44 - 3.2. Access Tokens . . . . . . . . . . . . . . . . . . . . . . 45 + 3.1. Request Continuation . . . . . . . . . . . . . . . . . . 43 + 3.2. Access Tokens . . . . . . . . . . . . . . . . . . . . . . 44 3.2.1. Single Access Token . . . . . . . . . . . . . . . . . 45 3.2.2. Multiple Access Tokens . . . . . . . . . . . . . . . 48 - 3.3. Interaction Modes . . . . . . . . . . . . . . . . . . . . 50 - 3.3.1. Redirection to an arbitrary URL . . . . . . . . . . . 51 + 3.3. Interaction Modes . . . . . . . . . . . . . . . . . . . . 49 + 3.3.1. Redirection to an arbitrary URL . . . . . . . . . . . 50 3.3.2. Launch of an application URL . . . . . . . . . . . . 51 - 3.3.3. Display of a Short User Code . . . . . . . . . . . . 52 - 3.3.4. Interaction Finish . . . . . . . . . . . . . . . . . 53 - 3.3.5. Extending Interaction Mode Responses . . . . . . . . 54 - 3.4. Returning User Information . . . . . . . . . . . . . . . 54 - 3.5. Returning Dynamically-bound Reference Handles . . . . . . 55 + 3.3.3. Display of a Short User Code . . . . . . . . . . . . 51 + 3.3.4. Interaction Finish . . . . . . . . . . . . . . . . . 52 + 3.3.5. Extending Interaction Mode Responses . . . . . . . . 53 + 3.4. Returning User Information . . . . . . . . . . . . . . . 53 + 3.5. Returning Dynamically-bound Reference Handles . . . . . . 54 3.6. Error Response . . . . . . . . . . . . . . . . . . . . . 56 - 3.7. Extending the Response . . . . . . . . . . . . . . . . . 57 - 4. Determining Authorization and Consent . . . . . . . . . . . . 57 - 4.1. Interaction Start Methods . . . . . . . . . . . . . . . . 60 - 4.1.1. Interaction at a Redirected URI . . . . . . . . . . . 61 - 4.1.2. Interaction at the User Code URI . . . . . . . . . . 61 - 4.1.3. Interaction through an Application URI . . . . . . . 62 - 4.2. Post-Interaction Completion . . . . . . . . . . . . . . . 62 + 3.7. Extending the Response . . . . . . . . . . . . . . . . . 56 + 4. Determining Authorization and Consent . . . . . . . . . . . . 56 + 4.1. Interaction Start Methods . . . . . . . . . . . . . . . . 59 + 4.1.1. Interaction at a Redirected URI . . . . . . . . . . . 60 + 4.1.2. Interaction at the User Code URI . . . . . . . . . . 60 + 4.1.3. Interaction through an Application URI . . . . . . . 61 + 4.2. Post-Interaction Completion . . . . . . . . . . . . . . . 61 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 - Callback . . . . . . . . . . . . . . . . . . . . . . 64 - 4.2.3. Calculating the interaction hash . . . . . . . . . . 65 - 5. Continuing a Grant Request . . . . . . . . . . . . . . . . . 66 - 5.1. Continuing After a Completed Interaction . . . . . . . . 68 - 5.2. Continuing During Pending Interaction . . . . . . . . . . 69 - 5.3. Modifying an Existing Request . . . . . . . . . . . . . . 70 + Callback . . . . . . . . . . . . . . . . . . . . . . 63 + 4.2.3. Calculating the interaction hash . . . . . . . . . . 64 + 5. Continuing a Grant Request . . . . . . . . . . . . . . . . . 65 + 5.1. Continuing After a Completed Interaction . . . . . . . . 67 + 5.2. Continuing During Pending Interaction . . . . . . . . . . 68 + 5.3. Modifying an Existing Request . . . . . . . . . . . . . . 69 5.4. Canceling a Grant Request . . . . . . . . . . . . . . . . 75 - 6. Token Management . . . . . . . . . . . . . . . . . . . . . . 76 - 6.1. Rotating the Access Token . . . . . . . . . . . . . . . . 76 - 6.2. Revoking the Access Token . . . . . . . . . . . . . . . . 78 - 7. Securing Requests from the Client Instance . . . . . . . . . 79 - 7.1. Key Formats . . . . . . . . . . . . . . . . . . . . . . . 79 - 7.1.1. Key References . . . . . . . . . . . . . . . . . . . 81 - 7.2. Presenting Access Tokens . . . . . . . . . . . . . . . . 81 - 7.3. Proving Possession of a Key with a Request . . . . . . . 82 - 7.3.1. Detached JWS . . . . . . . . . . . . . . . . . . . . 84 - 7.3.2. Attached JWS . . . . . . . . . . . . . . . . . . . . 88 - 7.3.3. Mutual TLS . . . . . . . . . . . . . . . . . . . . . 92 - 7.3.4. Demonstration of Proof-of-Possession (DPoP) . . . . . 94 - 7.3.5. HTTP Message Signing . . . . . . . . . . . . . . . . 96 - 7.3.6. OAuth Proof of Possession (PoP) . . . . . . . . . . . 99 - 8. Resource Access Rights . . . . . . . . . . . . . . . . . . . 102 - 8.1. Requesting Resources By Reference . . . . . . . . . . . . 106 - 9. Discovery . . . . . . . . . . . . . . . . . . . . . . . . . . 108 - 10. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 109 - 11. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 110 - 12. Security Considerations . . . . . . . . . . . . . . . . . . . 110 - 13. Privacy Considerations . . . . . . . . . . . . . . . . . . . 110 - 14. Normative References . . . . . . . . . . . . . . . . . . . . 110 - Appendix A. Document History . . . . . . . . . . . . . . . . . . 113 - Appendix B. Compared to OAuth 2.0 . . . . . . . . . . . . . . . 115 - Appendix C. Component Data Models . . . . . . . . . . . . . . . 117 - Appendix D. Example Protocol Flows . . . . . . . . . . . . . . . 117 - D.1. Redirect-Based User Interaction . . . . . . . . . . . . . 118 - D.2. Secondary Device Interaction . . . . . . . . . . . . . . 122 - D.3. No User Involvement . . . . . . . . . . . . . . . . . . . 125 - D.4. Asynchronous Authorization . . . . . . . . . . . . . . . 126 - D.5. Applying OAuth 2.0 Scopes and Client IDs . . . . . . . . 129 - Appendix E. JSON Structures and Polymorphism . . . . . . . . . . 131 - Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 132 + 6. Token Management . . . . . . . . . . . . . . . . . . . . . . 75 + 6.1. Rotating the Access Token . . . . . . . . . . . . . . . . 75 + 6.2. Revoking the Access Token . . . . . . . . . . . . . . . . 77 + 7. Securing Requests from the Client Instance . . . . . . . . . 78 + 7.1. Key Formats . . . . . . . . . . . . . . . . . . . . . . . 78 + 7.1.1. Key References . . . . . . . . . . . . . . . . . . . 80 + 7.2. Presenting Access Tokens . . . . . . . . . . . . . . . . 80 + 7.3. Proving Possession of a Key with a Request . . . . . . . 81 + 7.3.1. HTTP Message Signing . . . . . . . . . . . . . . . . 83 + 7.3.2. Mutual TLS . . . . . . . . . . . . . . . . . . . . . 87 + 7.3.3. Detached JWS . . . . . . . . . . . . . . . . . . . . 89 + 7.3.4. Attached JWS . . . . . . . . . . . . . . . . . . . . 93 + 8. Resource Access Rights . . . . . . . . . . . . . . . . . . . 97 + 8.1. Requesting Resources By Reference . . . . . . . . . . . . 100 + 9. Discovery . . . . . . . . . . . . . . . . . . . . . . . . . . 102 + 9.1. RS-first Method of AS Discovery . . . . . . . . . . . . . 103 + 10. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 105 + 11. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 105 + 12. Security Considerations . . . . . . . . . . . . . . . . . . . 105 + 13. Privacy Considerations . . . . . . . . . . . . . . . . . . . 105 + 14. Normative References . . . . . . . . . . . . . . . . . . . . 105 + Appendix A. Document History . . . . . . . . . . . . . . . . . . 108 + Appendix B. Compared to OAuth 2.0 . . . . . . . . . . . . . . . 110 + Appendix C. Component Data Models . . . . . . . . . . . . . . . 113 + Appendix D. Example Protocol Flows . . . . . . . . . . . . . . . 113 + D.1. Redirect-Based User Interaction . . . . . . . . . . . . . 113 + D.2. Secondary Device Interaction . . . . . . . . . . . . . . 117 + D.3. No User Involvement . . . . . . . . . . . . . . . . . . . 120 + D.4. Asynchronous Authorization . . . . . . . . . . . . . . . 121 + D.5. Applying OAuth 2.0 Scopes and Client IDs . . . . . . . . 124 + Appendix E. JSON Structures and Polymorphism . . . . . . . . . . 126 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 127 1. Introduction This protocol allows a piece of software, the client instance, to request delegated authorization to resource servers and to request direct information. This delegation is facilitated by an authorization server usually on behalf of a resource owner. The end- user operating the software may interact with the authorization server to authenticate, provide consent, and authorize the request. 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 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 different parties acting in each role, and is not to specify implementation details of each. Where appropriate, GNAP may make recommendations about internal implementation details, but these recommendations are to ensure the security of the overall deployment rather than to be prescriptive in the implementation. This protocol solves many of the same use cases as OAuth 2.0 [RFC6749], OpenID Connect [OIDC], and the family of protocols that have grown up around that ecosystem. However, GNAP is not an @@ -191,20 +198,51 @@ indicate line wrapping for long values, as per [RFC8792]. The "\" character and leading spaces on wrapped lines are not part of the value. 1.2. Roles The parties in GNAP perform actions under different roles. Roles are defined by the actions taken and the expectations leveraged on the 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 a particular instance of client software in the form of access tokens or other information (such as subject information). Client application operated by an end-user that consumes resources from one or several RSs, possibly requiring access privileges from one or several ASs. Example: a client can be a mobile application, a web application, etc. @@ -958,29 +996,22 @@ 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 end-user to determine their status as the RO. Section 2.4 interact (object) Describes the modes that the client instance has for allowing the RO to interact with the AS and modes for the client instance to receive updates when interaction is complete. 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 - 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: { "access_token": { "access": [ { "type": "photo-api", "actions": [ "read", @@ -998,39 +1029,38 @@ }, "dolphin-metadata" ] }, "client": { "display": { "name": "My Client Display Name", "uri": "https://example.net/client" }, "key": { - "proof": "jwsd", + "proof": "httpsig", "jwk": { "kty": "RSA", "e": "AQAB", "kid": "xyz-1", "alg": "RS256", "n": "kOB5rR4Jv0GMeL...." } } }, "interact": { "start": ["redirect"], "finish": { "method": "redirect", "uri": "https://client.example.net/return/123455", "nonce": "LKLTI25DK82FX4T4QFZC" } }, - "capabilities": ["ext1", "ext2"], "subject": { "formats": ["iss_sub", "opaque"], "assertions": ["id_token"] } } 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 otherwise specified by the signature mechanism. @@ -1062,29 +1092,29 @@ field is REQUIRED if used as part of a multiple access token request (Section 2.1.2), and is OPTIONAL otherwise. flags (array of strings) A set of flags that indicate desired attributes or behavior to be attached to the access token by the AS. This field is OPTIONAL. The values of the "flags" field defined by this specification are as follows: - bearer If this flag is included, the access token being requested is - a bearer token. If this flag is omitted, the access token is + "bearer" If this flag is included, the access token being requested + 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 the key's most recent rotation. Methods for presenting bound and bearer access tokens are described in Section 7.2. [[ See issue #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 request (Section 2.1), including receiving multiple access tokens (Section 3.2.2) in response to any single token request (Section 2.1.1) or a different number of access tokens than requested in a multiple access token request (Section 2.1.2). The "label" fields of the returned additional tokens are chosen by the AS. The client instance MUST be able to tell from the token response where and how it can use each of the access tokens. [[ See issue #37 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ issues/37) ]] @@ -1312,51 +1342,31 @@ AS policy, attestations within the "client" request, and other mechanisms. [[ See issue #44 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ issues/44) ]] 2.3.1. Identifying the Client Instance by Reference If the client instance has an instance identifier that the AS can use to determine appropriate key information, the client instance can - send this value in the "instance_id" field. The instance identifier - MAY be assigned to a client instance at runtime through the - Section 3.5 or MAY be obtained 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. + send this instance identifier as a direct reference value in lieu of + the "client" object. The instance identifier MAY be assigned to a + client instance at runtime through the Section 3.5 or MAY be obtained + in another fashion, such as a static registration process at the AS. "client": "client-541-ab" 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 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 MUST be rejected with an error. 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. 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 possession of it. 2.3.2. Providing Displayable Client Instance Information @@ -1771,47 +1781,21 @@ 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 none of the given locales are supported, the AS MAY use a default locale. 2.5.4. Extending Interaction Modes Additional interaction start modes, finish modes, and hints are defined in a registry TBD (Section 11). -2.6. Declaring Client Capabilities - - 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 +2.6. Extending The Grant Request The request object MAY be extended by registering new items in a registry TBD (Section 11). Extensions SHOULD be orthogonal to other parameters. Extensions MUST document any aspects where the extension item affects or influences the values or behavior of other request and response objects. 3. Grant Response In response to a client instance's request, the AS responds with a @@ -1848,57 +1832,58 @@ { "interact": { "redirect": "https://server.example.com/interact/4CF492ML\ VMSW9MKMXKHQ", "finish": "MBDOFXG4Y5CVJCX821LH" }, "continue": { "access_token": { "value": "80UPRY5NM33OMUKMKSKU", - "bound": true }, "uri": "https://server.example.com/tx" } } - 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.4) in the form of an opaque identifier. { "access_token": { "value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0", - "bound": false, + "flags": ["bearer"], "manage": "https://server.example.com/token/PRY5NM33O\ M4TB8N6BW7OZB8CDFONP219RP1L", }, "subject": { "sub_ids": [ { "format": "opaque", "id": "J2G8G8O4AZ" } ] } } - In this example, the AS is returning only a pair of subject - identifiers (Section 3.4) as both an email address and an opaque - identifier. + In this example, the AS is returning set of subject identifiers + (Section 3.4), simultaneously as an opaque identifier, an email + address, and a decentralized identifier (DID). { "subject": { "sub_ids": [ { "subject_type": "opaque", "id": "J2G8G8O4AZ" }, { "format": "email", "email": "user@example.com" + }, { + "format": "did", + "url": "did:example:123456" } ] } } 3.1. Request Continuation If the AS determines that the request can be continued with additional requests, it responds with the "continue" field. This field contains a JSON object with the following properties. @@ -1909,27 +1894,27 @@ continuation request (Section 5). wait (integer) RECOMMENDED. The amount of time in integer seconds the client instance SHOULD wait after receiving this continuation handle and calling the URI. access_token (object) REQUIRED. A unique access token for 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 in the request and MUST NOT be a "bearer" token. As a - consequence, the "bound" field of this access token is always the - boolean value "true" and the "key" field MUST be omitted. This - access token MUST NOT be usable at resources outside of the AS. - The client instance MUST present the access token in all requests - to the continuation URI as described in Section 7.2. [[ See issue - #66 (https://github.com/ietf-wg-gnap/gnap-core-protocol/issues/66) - ]] + consequence, the "flags" array of this access token MUST NOT + contain the string "bearer" and the "key" field MUST be omitted. + This access token MUST NOT be usable at resources outside of the + AS. The client instance MUST present the access token in all + requests to the continuation URI as described in Section 7.2. [[ + See issue #66 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ + issues/66) ]] { "continue": { "access_token": { "value": "80UPRY5NM33OMUKMKSKU" }, "uri": "https://server.example.com/continue", "wait": 60 } } @@ -1961,30 +1946,20 @@ has granted that access token, the AS responds with the "access_token" field. The value of this field is an object with the following properties. value (string) REQUIRED. The value of the access token as a string. The value is opaque to the client instance. The value SHOULD be limited to ASCII characters to facilitate transmission over HTTP headers within other protocols without requiring additional 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 single access token. The value of the "label" the client instance provided in the associated token request (Section 2.1), if 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 included and set to "true". manage (string) OPTIONAL. The management URI for this access token. If provided, the client instance MAY manage its access token as described in Section 6. This management URI is a function of the @@ -2003,37 +1978,57 @@ 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 RS at any point prior to its expiration. key (object / string) OPTIONAL. The key that the token is bound to, 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. The client instance MUST be able to dereference or process the key information in order to be able to sign the request. - durable (boolean) OPTIONAL. Flag indicating a hint of AS behavior - on token rotation. If this flag is set to the value "true", 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 - 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. + flags (array of strings) OPTIONAL. A set of flags that represent + attributes or behaviors of the access token issued by the AS. - split (boolean) 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. + The values of the "flags" field defined by this specification are as + follows: + + "bearer" This flag indicates whether the token is bound to the + 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 to the client instance's key used in the initial request, with a management URL, and that has access to three described resources (one using an object and two described by reference strings). "access_token": { "value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0", "manage": "https://server.example.com/token/PRY5NM33O\ M4TB8N6BW7OZB8CDFONP219RP1L", @@ -2050,38 +2045,39 @@ "https://resource.local/other" ], "datatypes": [ "metadata", "images" ] }, "read", "dolphin-metadata" ] } + The following non-normative example shows a single bearer access token with access to two described resources. "access_token": { "value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0", - "bound": false, + "flags": ["bearer"], "access": [ "finance", "medical" ] } If the client instance requested a single access token (Section 2.1.1), the AS MUST NOT respond with the multiple access token structure unless the client instance sends the "split" flag as described in Section 2.1.1. 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/ issues/69) ]] 3.2.2. Multiple Access Tokens If the client instance has requested multiple access tokens and 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 members of which are distinct access tokens as described in @@ -2120,35 +2116,35 @@ tokens are included in the response the requested names appropriate names. If the client instance requested multiple access tokens (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 cases, the AS responds with a multiple access token structure containing one access token. 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": [ { "label": "split-1", "value": "8N6BW7OZB8CDFONP219-OS9M2PMHKUR64TBRP1LT0", - "split": true, + "flags": ["split"], "manage": "https://server.example.com/token/PRY5NM33O\ M4TB8N6BW7OZB8CDFONP219RP1L", "access": [ "fruits" ] }, { "label": "split-2", "value": "FG7VGZZPJ3IZEMN21EVU71FHCAR-UFGLO2FDAP4J1", - "split": true, + "flags": ["split"], "access": [ "vegetables" ] } } Each access token MAY be bound to different keys with different proofing mechanisms. If token management (Section 6) is allowed, each access token SHOULD have different "manage" URIs. @@ -2819,33 +2814,44 @@ 4.2.3. Calculating the interaction hash The "hash" parameter in the request to the client instance's callback URL ties the front channel response to an ongoing request by using values known only to the parties involved. This security mechanism allows the client instance to protect itself against several kinds of session fixation and injection attacks. The AS MUST always provide this hash, and the client instance MUST validate the hash when received. - To calculate the "hash" value, the party doing the calculation first - takes the "nonce" value sent by the client instance in the - interaction section of the initial request (Section 2.5.2), the AS's - nonce value from the interaction finish response (Section 3.3.4), and - the "interact_ref" sent to the client instance's callback URL. These - three values are concatenated to each other in this order using a - single newline character as a separator between the fields. There is - no padding or whitespace before or after any of the lines, and no - trailing newline character. + To calculate the "hash" value, the party doing the calculation + creates a hash string by concatenating the following values in the + following order using a single newline ("\\n") character to separate + them: + + * the "nonce" value sent by the client instance in the interaction + "finish" section of the initial request (Section 2.5.2) + + * 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 MBDOFXG4Y5CVJCX821LH 4IFWWIKYBC2PQ6U56NL1 + https://server.example.com/tx The party then hashes this string with the appropriate algorithm based on the "hash_method" parameter of the "callback". If the "hash_method" value is not present in the client instance's request, the algorithm defaults to "sha3". [[ See issue #56 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ issues/56) ]] 4.2.3.1. SHA3-512 @@ -2890,50 +2896,53 @@ Section 7.2 and present proof of the client instance's key (or its most recent rotation) by signing the request as described in Section 7.3. The AS MUST validate all keys presented by the client instance or referenced in an ongoing request for each call within that request. [[ See issue #85 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ issues/85) ]] 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 Authorization: GNAP 80UPRY5NM33OMUKMKSKU 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 specific ongoing request is being accessed, using a combination of the continuation URL, the provided access token, and the client instance identified by the key signature. If the AS cannot determine a single active grant request to map the continuation request to, the AS MUST return an error. The ability to continue an already-started request allows the client instance to perform several important functions, including presenting additional information from interaction, modifying the initial request, and getting the current state of the request. All requests to the continuation API are protected by this bound access token. For example, here the client instance makes a POST request to a stable continuation endpoint URL with the interaction reference (Section 5.1), includes the access token, and signs with - detached JWS: + HTTP Message Signatures: POST /continue HTTP/1.1 Host: server.example.com Content-Type: application/json Authorization: GNAP 80UPRY5NM33OMUKMKSKU - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "interact_ref": "4IFWWIKYBC2PQ6U56NL1" } If a "wait" parameter was included in the continuation response (Section 3.1), the client instance MUST NOT call the continuation URI prior to waiting the number of seconds indicated. If no "wait" period is indicated, the client instance SHOULD wait at least 5 seconds. If the client instance does not respect the given wait @@ -2961,21 +2970,23 @@ When the AS responds to the client instance's "finish" method as in Section 4.2.1, this response includes an interaction reference. The client instance MUST include that value as the field "interact_ref" in a POST request to the continuation URI. POST /continue HTTP/1.1 Host: server.example.com Content-Type: application/json Authorization: GNAP 80UPRY5NM33OMUKMKSKU - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "interact_ref": "4IFWWIKYBC2PQ6U56NL1" } 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 continuation calls after this request, the client instance MUST NOT include the interaction reference. If the AS detects a client instance submitting the same interaction reference multiple times, @@ -3018,21 +3028,22 @@ When the client instance does not include a "finish" parameter, the 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 request to the continuation URI as in Section 5.1, but does not include a message body. POST /continue HTTP/1.1 Host: server.example.com Content-Type: application/json Authorization: GNAP 80UPRY5NM33OMUKMKSKU - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... The Section 3 MAY contain any newly-created access tokens (Section 3.2) or newly-released subject claims (Section 3.4). The response MAY contain a new "continue" response (Section 3.1) as described above. If a "continue" field is included, it SHOULD include a "wait" field to facilitate a reasonable polling rate by the client instance. The response SHOULD NOT contain interaction responses (Section 3.3). For example, if the request has not yet been authorized by the RO, @@ -3128,21 +3139,23 @@ contain a new "continue" response (Section 3.1) as described above. If interaction can occur, the response SHOULD contain interaction responses (Section 3.3) as well. For example, a client instance initially requests a set of resources using references: POST /tx HTTP/1.1 Host: server.example.com Content-Type: application/json - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "access_token": { "access": [ "read", "write" ] }, "interact": { "start": ["redirect"], "finish": { @@ -3177,21 +3189,23 @@ This "continue" field allows the client instance to make an eventual continuation call. In the future, the client instance realizes that it no longer needs "write" access and therefore modifies its ongoing request, here asking for just "read" access instead of both "read" and "write" as before. PATCH /continue HTTP/1.1 Host: server.example.com Content-Type: application/json Authorization: GNAP 80UPRY5NM33OMUKMKSKU - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "access_token": { "access": [ "read" ] } ... } @@ -3212,29 +3226,30 @@ "uri": "https://server.example.com/continue", "wait": 30 }, "access_token": { "value": "0EVKC7-2ZKwZM_6N760", "access": [ "read" ] } } - For another example, the client instance initially requests read-only access but later needs to step up its access. The initial request could look like this example. POST /tx HTTP/1.1 Host: server.example.com Content-Type: application/json - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "access_token": { "access": [ "read" ] }, "interact": { "start": ["redirect"], "finish": { @@ -3277,21 +3290,23 @@ and the callback is intended for one-time-use, a new one needs to be included in order to use the callback again. [[ See issue #97 (https://github.com/ietf-wg-gnap/gnap-core-protocol/ issues/97) ]] PATCH /continue HTTP/1.1 Host: server.example.com Content-Type: application/json Authorization: GNAP 80UPRY5NM33OMUKMKSKU - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "access_token": { "access": [ "read", "write" ] }, "interact": { "start": ["redirect"], "finish": { @@ -3314,21 +3329,22 @@ 5.4. Canceling a Grant Request If the client instance wishes to cancel an ongoing grant request, it makes an HTTP DELETE request to the continuation URI. DELETE /continue HTTP/1.1 Host: server.example.com Content-Type: application/json Authorization: GNAP 80UPRY5NM33OMUKMKSKU - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... If the request is successfully cancelled, the AS responds with an HTTP 202. The AS SHOULD revoke all associated access tokens. 6. Token Management If an access token response includes the "manage" parameter as 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 following sections. Other actions are undefined by this @@ -3352,21 +3368,23 @@ 6.1. Rotating the Access Token The client instance makes an HTTP POST to the token management URI, sending the access token in the appropriate header and signing the request with the appropriate key. POST /token/PRY5NM33OM4TB8N6BW7OZB8CDFONP219RP1L HTTP/1.1 Host: server.example.com Authorization: GNAP OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 - Detached-JWS: eyj0.... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... The AS validates that the token presented is associated with the management URL, that the AS issued the token to the given client instance, and that the presented key is appropriate to the token. If the access token has expired, the AS SHOULD honor the rotation request to the token management URL since it is likely that the client instance is attempting to refresh the expired token. To 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 @@ -3426,21 +3444,22 @@ token management URI to indicate to the AS that the AS should invalidate the access token for all purposes. The client instance makes an HTTP DELETE request to the token management URI, presenting the access token and signing the request with the appropriate key. DELETE /token/PRY5NM33OM4TB8N6BW7OZB8CDFONP219RP1L HTTP/1.1 Host: server.example.com Authorization: GNAP OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 - Detached-JWS: eyj0.... + Signature-Input: sig1=... + Signature: sig1=... 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 access token, if possible, and return an HTTP 204 response code. 204 No Content Though the AS MAY revoke an access token at any time for any reason, the token management function is specifically for the client instance's use. If the access token has already expired or has been @@ -3461,22 +3480,23 @@ * 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 to the AS to initiate a negotiation. * 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 RS, and only with access tokens that are not bound to any key as described in Section 3.2.1. * 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 - protocol of GNAP. + unsecured request. This type of request is used optionally for + calls to the RS as part of an RS-first discovery process as + described in Section 9.1. 7.1. Key Formats Several different places in GNAP require the presentation of key 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 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 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 @@ -3504,26 +3524,26 @@ the request, with optional internal whitespace per [RFC7468]. The PEM header and footer are optionally removed. cert#S256 (string) The certificate thumbprint calculated as per OAuth-MTLS [RFC8705] in base64 URL encoding. Note that this format does not include the full public key. Additional key formats are defined in a registry TBD (Section 11). This non-normative example shows a single key presented in multiple - formats. This key is intended to be used with the detached JWS - (Section 7.3.1) proofing mechanism, as indicated by the "proof" - field. + formats. This example key is intended to be used with the HTTP + Message Signatures ({{httpsig-binding}}) proofing mechanism, as + indicated by the "httpsig" value of the "proof" field. "key": { - "proof": "jwsd", + "proof": "httpsig", "jwk": { "kty": "RSA", "e": "AQAB", "kid": "xyz-1", "alg": "RS256", "n": "kOB5rR4Jv0GMeLaY6_It_r3ORwdf8ci_JtffXyaSx8xY..." }, "cert": "MIIEHDCCAwSgAwIBAgIBATANBgkqhkiG9w0BAQsFA..." } @@ -3546,72 +3566,71 @@ specification. 7.2. Presenting Access Tokens 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 method is associated with the key. This information is conveyed in the "bound" and "key" parameters in the single (Section 3.2.1) and multiple access tokens (Section 3.2.2) responses. - If the "bound" value is the boolean "true" and the "key" is absent, - the access token MUST be sent using the same key and proofing - mechanism that the client instance used in its initial request (or - its most recent rotation). + If the "flags" field does not contain the "bearer" flag and the "key" + is absent, the access token MUST be sent using the same key and + proofing mechanism that the client instance used in its initial + request (or its most recent rotation). - If the "bound" value is the boolean "true" and the "key" value is an - object as described in Section 7.1, the access token MUST be sent - using the key and proofing mechanism defined by the value of the - "proof" field within the key object. + If the "flags" field does not contain the "bearer" flag and the "key" + value is an object as described in Section 7.1, the access token MUST + be sent using the key and proofing mechanism defined by the value of + the "proof" field within the key object. The access token MUST be sent using the HTTP "Authorization" request 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 - 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 - Detached-JWS: eyj0.... + Signature-Input: sig1=(authorization);... + Signature: sig1=... - If the "bound" value is the boolean "false", the access token is a - bearer token that MUST be sent using the "Authorization Request + If the "flags" field contains the "bearer" flag, the access token is + a bearer token that MUST be sent using the "Authorization Request Header Field" method defined in [RFC6750]. Authorization: Bearer OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0 The "Form-Encoded Body Parameter" and "URI Query Parameter" methods of [RFC6750] MUST NOT be used. [[ See issue #104 (https://github.com/ietf-wg-gnap/gnap-core- protocol/issues/104) ]] 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 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 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 follows: - jwsd A detached JWS signature header - - jws Attached JWS payload + httpsig HTTP Signing signature header mtls Mutual TLS certificate verification - dpop OAuth Demonstration of Proof-of-Possession key proof header - - httpsig HTTP Signing signature header + jwsd A detached JWS signature header - oauthpop OAuth PoP key proof authentication header + jws Attached JWS payload Additional proofing methods are defined by a registry TBD (Section 11). All key binding methods used by this specification MUST cover all relevant portions of the request, including anything that would change the nature of the request, to allow for secure validation of the request. Relevant aspects include the URI being called, the HTTP method being used, any relevant HTTP headers and values, and the HTTP message body itself. The verifier of the signed message MUST @@ -3678,94 +3697,66 @@ M40ql8u8J6vc2GmQGfokLlPQ6XLSCY68_xkTXrhoU1f-eDntkhP7L6XawSK\ Onv5F2H7wyBQ75HUmHTg8AK2B_vRlMyFKjXbVlzKf4kvqChSGEz4IjQ", "n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8BfYdHsFzAt\ YKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZGYX\ jHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZx\ e0jRETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0\ bunS0K3bA_3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kO\ zywzwPTuq-cVQDyEN7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" } -7.3.1. Detached JWS - - 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 +7.3.1. HTTP Message Signing - htm (string) The HTTP Method used to make this request, as an - uppercase ASCII string. REQUIRED + This method is indicated by "httpsig" in the "proof" field. The + 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 - and query components and no fragment component. REQUIRED + The covered content of the signature MUST include the following: - created (integer) A timestamp of when the signature was created, in - integer seconds since UNIX Epoch + @request-target: the target of the HTTP request - 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. REQUIRED if the - request protects an access token. + digest: The Digest header as defined in [RFC3230]. When the request + message has a body, the signer MUST calculate this header value + and the verifier MUST validate this header. - If the HTTP request has a message body, such as an HTTP POST or PUT - 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. + When the request is bound to an access token, the covered content + MUST also include: - The client instance presents the signed object in compact form - [RFC7515] in the Detached-JWS HTTP Header field. + authorization: The Authorization header used to present the access + token as discussed in Section 7.2. - In this example, the JOSE Header contains the following parameters: + Other covered content MAY also be included. - { - "alg": "RS256", - "kid": "gnap-rsa", - "uri": "https://server.example.com/gnap", - "htm": "POST", - "typ": "gnap-binding+jwsd", - "created": 1618884475 - } + 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 + algorithm used MUST be the JWS algorithm denoted by the key's "alg" + field, and the explicit "alg" signature parameter MUST NOT be + included. - The request body is the following JSON object: + In this example, the message 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": "jwsd", + "proof": "httpsig", "key": { "jwk": { "kid": "gnap-rsa", "kty": "RSA", "e": "AQAB", "alg": "RS256", "n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ @@ -3773,229 +3764,97 @@ N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" } } "display": { "name": "My Client Display Name", "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 Host: server.example.com Content-Type: application/json - Content-Length: 983 - Detached-JWS: eyJhbGciOiJSUzI1NiIsImNyZWF0ZWQiOjE2MTg4ODQ0NzUsImh0b\ - SI6IlBPU1QiLCJraWQiOiJnbmFwLXJzYSIsInR5cCI6ImduYXAtYmluZGluZytqd3\ - NkIiwidXJpIjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20vZ25hcCJ9.PGiVuO\ - ZUcN1tRtUS6tx2b4cBgw9mPgXG3IPB3wY7ctc.fUq-SV-A1iFN2MwCRW_yolVtT2_\ - TZA2h5YeXUoi5F2Q2iToC0Tc4drYFOSHIX68knd68RUA7yHqCVP-ZQEd6aL32H69e\ - 9zuMiw6O_s4TBKB3vDOvwrhYtDH6fX2hP70cQoO-47OwbqP-ifkrvI3hVgMX9TfjV\ - eKNwnhoNnw3vbu7SNKeqJEbbwZfpESaGepS52xNBlDNMYBQQXxM9OqKJaXffzLFEl\ - -Xe0UnfolVtBraz3aPrPy1C6a4uT7wLda3PaTOVtgysxzii3oJWpuz0WP5kRujzDF\ - wX_EOzW0jsjCSkL-PXaKSpZgEjNjKDMg9irSxUISt1C1T6q3SzRgfuQ - - { - "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: + Content-Length: 986 + Digest: SHA-256=98QzyNVYpdgTrWBKpC4qFSCmmR+CrwwvUoiaDCSjKxw= + Signature-Input: sig1=("@request-target" "host" "content-type" \ + "digest" "content-length");created=1618884475;keyid="gnap-rsa" + Signature: \ + sig1=:axj8FLOvEWBcwh+Xk6VTTKXxqo4XNygleTDJ8h3ZJfi1sSmWrRtyo9RG/dc\ + miZmdszRjWbg+/ixVZpA4BL3AOwEOxxtmHAXNB8uJ0I3tfbs6Suyk4sEo8zPr+MJq\ + MjxdJEUgAQAy2AH+wg5a7CKq4IdLTulFK9njUIeG7MygHumeiumM3DbDQAHgF46dV\ + q5UC6KJnqhGM1rFC128jd2D0sgWKCUgKGCHtfR159zfKWcEO9krsLoOnCdTzm1UyD\ + 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": "jws", + "proof": "httpsig", "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/" }, - }, - "subject": { - "formats": ["iss_sub", "opaque"] } } - This leads to the following full HTTP request message: - - POST /gnap HTTP/1.1 - Host: server.example.com - Content-Type: application/jose - 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. + If the HTTP Message includes a message body, the verifier MUST + calculate and verify the value of the "Digest" header. The verifier + MUST ensure that the signature includes all required covered content. + The verifier MUST validate the signature against the expected key of + the signer. -7.3.3. Mutual TLS +7.3.2. Mutual TLS This method is indicated by "mtls" in the "proof" field. The signer presents its TLS client certificate during TLS negotiation with the verifier. In this example, the certificate is communicated to the application through the "Client-Cert" header from a TLS reverse proxy, leading to the following full HTTP request message: POST /gnap HTTP/1.1 @@ -4071,261 +3931,150 @@ Note that in many instances, the verifier will not do a full certificate chain validation of the presented TLS client certificate, 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- first-use. [[ See issue #110 (https://github.com/ietf-wg-gnap/gnap-core- protocol/issues/110) ]] -7.3.4. Demonstration of Proof-of-Possession (DPoP) - - 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=" - } +7.3.3. Detached JWS - 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 - Host: server.example.com - 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 + To protect the request, the JOSE header of the signature contains the + following parameters: - { - "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/" - }, - } - } + 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. - The verifier MUST parse and validate the DPoP proof header as defined - in [I-D.ietf-oauth-dpop]. If the HTTP message request includes a - message body, the verifier MUST calculate the digest of the body and - compare it to the "htd" value. The verifier MUST ensure the key - presented in the DPoP proof header is the same as the expected key of - the signer. + 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". -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 - sender creates an HTTP Message Signature as described in - [I-D.ietf-httpbis-message-signatures]. + htm (string) The HTTP Method used to make this request, as an + uppercase ASCII string. REQUIRED - 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 - message has a body, the signer MUST calculate this header value - and the verifier MUST validate this header. + 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. REQUIRED if the + request protects an access token. - When the request is bound to an access token, the covered content - MUST also include: + If the HTTP request has a message body, such as an HTTP POST or PUT + 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 - token as discussed in Section 7.2. + The client instance presents the signed object in compact form + [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 - algorithm used MUST be the JWS algorithm denoted by the key's "alg" - field, and the explicit "alg" signature parameter MUST NOT be - included. + { + "alg": "RS256", + "kid": "gnap-rsa", + "uri": "https://server.example.com/gnap", + "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": [ "dolphin-metadata" ] }, "interact": { "start": ["redirect"], "finish": { "method": "redirect", "uri": "https://client.foo/callback", "nonce": "VJLO6A4CAYLBXHTR0KRO" } }, "client": { - "proof": "httpsig", + "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/" }, } } - This body is hashed for the Digest header using SHA-256 into the - following encoded value: - SHA-256=98QzyNVYpdgTrWBKpC4qFSCmmR+CrwwvUoiaDCSjKxw= - - The HTTP message signature input string is calculated to be the - following: + This is hashed to the following Base64 encoded value: - "@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" + PGiVuOZUcN1tRtUS6tx2b4cBgw9mPgXG3IPB3wY7ctc - This leads to the following full HTTP message request: + This leads to the following full HTTP request message: POST /gnap HTTP/1.1 Host: server.example.com Content-Type: application/json - Content-Length: 986 - Digest: SHA-256=98QzyNVYpdgTrWBKpC4qFSCmmR+CrwwvUoiaDCSjKxw= - Signature-Input: sig1=("@request-target" "host" "content-type" \ - "digest" "content-length");created=1618884475;keyid="gnap-rsa" - Signature: \ - sig1=:axj8FLOvEWBcwh+Xk6VTTKXxqo4XNygleTDJ8h3ZJfi1sSmWrRtyo9RG/dc\ - miZmdszRjWbg+/ixVZpA4BL3AOwEOxxtmHAXNB8uJ0I3tfbs6Suyk4sEo8zPr+MJq\ - MjxdJEUgAQAy2AH+wg5a7CKq4IdLTulFK9njUIeG7MygHumeiumM3DbDQAHgF46dV\ - q5UC6KJnqhGM1rFC128jd2D0sgWKCUgKGCHtfR159zfKWcEO9krsLoOnCdTzm1UyD\ - DMjkIjqeN/1j8PdMJaRAwV4On079O0DVu6bl1jVtkzo/e/ZmwPr/X436V4xiw/hZt\ - w4sfNsSbmsT0+UAQ20X/xaw==: + Content-Length: 983 + Detached-JWS: eyJhbGciOiJSUzI1NiIsImNyZWF0ZWQiOjE2MTg4ODQ0NzUsImh0b\ + SI6IlBPU1QiLCJraWQiOiJnbmFwLXJzYSIsInR5cCI6ImduYXAtYmluZGluZytqd3\ + NkIiwidXJpIjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20vZ25hcCJ9.PGiVuO\ + ZUcN1tRtUS6tx2b4cBgw9mPgXG3IPB3wY7ctc.fUq-SV-A1iFN2MwCRW_yolVtT2_\ + TZA2h5YeXUoi5F2Q2iToC0Tc4drYFOSHIX68knd68RUA7yHqCVP-ZQEd6aL32H69e\ + 9zuMiw6O_s4TBKB3vDOvwrhYtDH6fX2hP70cQoO-47OwbqP-ifkrvI3hVgMX9TfjV\ + eKNwnhoNnw3vbu7SNKeqJEbbwZfpESaGepS52xNBlDNMYBQQXxM9OqKJaXffzLFEl\ + -Xe0UnfolVtBraz3aPrPy1C6a4uT7wLda3PaTOVtgysxzii3oJWpuz0WP5kRujzDF\ + wX_EOzW0jsjCSkL-PXaKSpZgEjNjKDMg9irSxUISt1C1T6q3SzRgfuQ { "access_token": { "access": [ "dolphin-metadata" ] }, "interact": { "start": ["redirect"], "finish": { "method": "redirect", "uri": "https://client.foo/callback", "nonce": "VJLO6A4CAYLBXHTR0KRO" } }, "client": { - "proof": "httpsig", + "proof": "jwsd", "key": { "jwk": { "kid": "gnap-rsa", "kty": "RSA", "e": "AQAB", "alg": "RS256", "n": "hYOJ-XOKISdMMShn_G4W9m20mT0VWtQBsmBBkI2cmRt4Ai8Bf\ YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ @@ -4329,177 +4078,174 @@ YdHsFzAtYKOjpBR1RpKpJmVKxIGNy0g6Z3ad2XYsh8KowlyVy8IkZ8NMwSrcUIBZG\ YXjHpwjzvfGvXH_5KJlnR3_uRUp4Z4Ujk2bCaKegDn11V2vxE41hqaPUnhRZxe0jR\ ETddzsE3mu1SK8dTCROjwUl14mUNo8iTrTm4n0qDadz8BkPo-uv4BC0bunS0K3bA_\ 3UgVp7zBlQFoFnLTO2uWp_muLEWGl67gBq9MO3brKXfGhi3kOzywzwPTuq-cVQDyE\ N7aL0SxCb3Hc4IdqDaMg8qHUyObpPitDQ" } } "display": { "name": "My Client Display Name", "uri": "https://client.foo/" + }, } } - If the HTTP Message includes a message body, the verifier MUST - calculate and verify the value of the "Digest" header. The verifier - MUST ensure that the signature includes all required covered content. - The verifier MUST validate the signature against the expected key of - the signer. + 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.6. OAuth Proof of Possession (PoP) +7.3.4. Attached JWS - This method is indicated by "oauthpop" in the "proof" field. The - signer creates an HTTP Authorization PoP header as described in - [I-D.ietf-oauth-signed-http-request] section 4, with the following - additional requirements: + This method is indicated by "jws" in the "proof" field. A JWS + [RFC7515] object is created as follows: - * The "at" (access token) field MUST be omitted unless this method - is being used in conjunction with an access token as in - Section 7.2. [[ See issue #112 (https://github.com/ietf-wg-gnap/ - gnap-core-protocol/issues/112) ]] + 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". - * The "b" (body hash) field MUST be calculated and included, if the - message includes an entity body (such as a PUT or PATCH request). + To protect the request, the JWS header MUST contain the following + additional parameters. - * All components of the URL MUST be calculated and included, - including query parameters "q", path "p", and host "u". + typ (string) The type header, value "gnap-binding+jws". - * The "m" (method) field MUST be included - In this example, the request message body is the following JSON - object + htm (string) The HTTP Method used to make this request, as an + uppercase ASCII string. - { - "access_token": { - "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/" - }, - } - } + uri (string) The HTTP URI used for this request, including all path + and query components and no fragment component. - 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 - { - "alg": "RS256", - "kid": "gnap-rsa" - } - After calculating the hashes for the body, headers, and URL - components, the JWS Payload is the following: + 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.3. + + In this example, the JOSE header contains the following parameters: { - "u": "server.example.com", - "p": "/gnap", - "m": "POST", - "ts": 1618884475, - "b": "sCvbP9VqOcq4LHkVDcayon2MoT4xPGc49TEnqsr6WYE", - "h": [ - [ - "content-type", - "content-length" - ], - "EJit2-669uk8JUzLJbidMFRkATuZOimvCOieXPjtEmU" - ] + "alg": "RS256", + "kid": "gnap-rsa", + "uri": "https://server.example.com/gnap", + "htm": "POST", + "typ": "gnap-binding+jwsd", + "created": 1618884475 } - This leads to the following HTTP message request: - - 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 + The request body, used as the JWS Payload, 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": "oauthpop", + "proof": "jws", "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/" }, + }, + "subject": { + "formats": ["iss_sub", "opaque"] } } - [[ See issue #113 (https://github.com/ietf-wg-gnap/gnap-core- - protocol/issues/113) ]] + This leads to the following full HTTP request message: - The verifier MUST parse the JWS object of the PoP header. The - verifier MUST validate the signature of the header against the - expected key of the signer. The verifier MUST ensure that all - required parts of the message are covered by the signature. The - verifier MUST ensure that all components of the signature contain - correct values. + POST /gnap HTTP/1.1 + Host: server.example.com + Content-Type: application/jose + 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. 8. Resource Access Rights GNAP provides a rich structure for describing the protected resources hosted by RSs and accessed by client software. This structure is used when the client instance requests an access token (Section 2.1) and when an access token is returned (Section 3.2). 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 @@ -4540,20 +4286,25 @@ datatypes (array of strings) The kinds of data available to the client instance at the RS's API as an array of strings. For example, a client instance asking for access to raw "image" data and "metadata" at a photograph API. identifier (string) A string identifier indicating a specific resource at the RS. For example, a patient identifier for a 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 access (read, write, delete) to each of two different locations and two different data types (metadata, images) for a single access token using the fictitious "photo-api" type definition. "access": [ { "type": "photo-api", "actions": [ "read", @@ -4749,28 +4500,29 @@ endpoint to retrieve the server's discovery information. The AS MUST respond with a JSON document containing the following information: grant_request_endpoint (string) REQUIRED. The location of the AS's grant request endpoint. The location MUST be a URL [RFC3986] with a scheme component that MUST be https, a host component, and optionally, port, path and query components and no fragment components. This URL MUST match the URL the client instance used to make the discovery request. - capabilities (array of strings) OPTIONAL. A list of the AS's - capabilities. The values of this result MAY be used by the client - instance in the capabilities section (Section 2.6) of the request. + interaction_start_modes_supported (array of strings) OPTIONAL. A + list of the AS's interaction start methods. The values of this + 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 - of the AS's interaction methods. The values of this list - correspond to the possible fields in the interaction section - (Section 2.5) of the request. + interaction_finish_methods_supported (array of strings) OPTIONAL. A + list of the AS's interaction finish methods. The values of this + list correspond to the possible values for the method element of + the interaction finish section (Section 2.5.2) of the request. key_proofs_supported (array of strings) OPTIONAL. A list of the AS's supported key proofing mechanisms. The values of this list correspond to possible values of the "proof" field of the key section (Section 7.1) of the request. subject_formats_supported (array of strings) OPTIONAL. A list of the AS's supported subject identifier types. The values of this list correspond to possible values of the subject identifier section (Section 2.2) of the request. @@ -4781,29 +4533,80 @@ (Section 2.2) of the request. The information returned from this method is for optimization 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 given client instance can be registered with the "mtls" key proofing mechanism, but the AS also returns other proofing methods, then the AS will deny a request from that client instance using a different 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 The editors would like to thank the feedback of the following individuals for their reviews, implementations, and contributions: - Aaron Parecki, Annabelle Backman, Dick Hardt, Dmitri Zagidulin, - Dmitry Barinov, Fabien Imbault, Francis Pouatcha, George Fletcher, - Haardik Haardik, Hamid Massaoud, Jacky Yuan, Joseph Heenan, Justin - Richer, Kathleen Moriarty, Mike Jones, Mike Varley, Nat Sakimura, - Takahiko Kawasaki, Takahiro Tsuchiya. + Aeke Axeland, Aaron Parecki, Adam Omar Oueidat, Annabelle Backman, + Dick Hardt, Dmitri Zagidulin, Dmitry Barinov, Fabien Imbault, Francis + Pouatcha, George Fletcher, Haardik Haardik, Hamid Massaoud, Jacky + Yuan, Joseph Heenan, Justin Richer, Kathleen Moriarty, Mike Jones, + Mike Varley, Nat Sakimura, Takahiko Kawasaki, Takahiro Tsuchiya. The editors would also like to thank the GNAP working group design team of Kathleen Moriarty, Fabien Imbault, Dick Hardt, Mike Jones, and Justin Richer, who incorporated elements from the XAuth and XYZ proposals to create the first version of this document. In addition, the editors would like to thank Aaron Parecki and Mike Jones for insights into how to integrate identity and authentication systems into the core protocol, and Justin Richer and Dick Hardt for the use cases, diagrams, and insights provided in the XYZ and XAuth @@ -4837,57 +4640,54 @@ 14. Normative References [BCP195] Sheffer, Y., Holz, R., and P. Saint-Andre, "Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)", May 2015, . [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, + . [I-D.ietf-httpbis-message-signatures] Backman, A., Richer, J., and M. Sporny, "Signing HTTP Messages", Work in Progress, Internet-Draft, draft-ietf- - httpbis-message-signatures-04, 21 April 2021, + httpbis-message-signatures-05, 8 June 2021, . - - [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, . + message-signatures-05.txt>. [I-D.ietf-oauth-rar] Lodderstedt, T., Richer, J., and B. Campbell, "OAuth 2.0 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, . + 05.txt>. [I-D.ietf-oauth-signed-http-request] Richer, J., Bradley, J., and H. Tschofenig, "A Method for Signing HTTP Requests for OAuth", Work in Progress, Internet-Draft, draft-ietf-oauth-signed-http-request-03, 8 August 2016, . [I-D.ietf-secevent-subject-identifiers] Backman, A. and M. Scurtescu, "Subject Identifiers for 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, . + subject-identifiers-08.txt>. [OIDC] Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and C. Mortimore, "OpenID Connect Core 1.0 incorporating errata set 1", November 2014, . [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, . @@ -4946,22 +4746,48 @@ DOI 10.17487/RFC8705, February 2020, . [RFC8792] Watsen, K., Auerswald, E., Farrel, A., and Q. Wu, "Handling Long Lines in Content of Internet-Drafts and RFCs", RFC 8792, DOI 10.17487/RFC8792, June 2020, . 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 "interaction_methods_supported". - Changed "key_proofs" to "key_proofs_supported". - Changed "assertions" to "assertions_supported". - Updated discovery and field names for subject formats. - Add an appendix to provide protocol rationale, compared to @@ -5184,21 +5011,23 @@ 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 Authorization Code grant type. The client instance initiates the request to the AS. Here the client instance identifies itself using its public key. POST /tx HTTP/1.1 Host: server.example.com Content-Type: application/json - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "access_token": { "access": [ { "actions": [ "read", "write", "dolphin" ], @@ -5208,21 +5037,21 @@ ], "datatypes": [ "metadata", "images" ] } ], }, "client": { "key": { - "proof": "jwsd", + "proof": "httpsig", "jwk": { "kty": "RSA", "e": "AQAB", "kid": "xyz-1", "alg": "RS256", "n": "kOB5rR4Jv0GMeLaY6_It_r3ORwdf8ci_JtffXyaSx8..." } } }, "interact": { @@ -5284,21 +5113,23 @@ out by validating session information and retrieves the stored pending request. The client instance uses the values in this to validate the hash parameter. The client instance then calls the continuation URL and presents the handle and interaction reference in the request body. The client instance signs the request as above. POST /continue HTTP/1.1 Host: server.example.com Content-Type: application/json Authorization: GNAP 80UPRY5NM33OMUKMKSKU - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "interact_ref": "4IFWWIKYBC2PQ6U56NL1" } The AS retrieves the pending request based on the handle and issues a bearer access token and returns this to the client instance. HTTP/1.1 200 OK Content-Type: application/json @@ -5340,21 +5171,23 @@ 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 needs to poll for updates while waiting for the user to authorize the request. The client instance initiates the request to the AS. POST /tx HTTP/1.1 Host: server.example.com Content-Type: application/json - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "access_token": { "access": [ "dolphin-metadata", "some other thing" ], }, "client": "7C7C4AZ9KHRS6X63AJAO", "interact": { "start": ["redirect", "user_code"] @@ -5403,21 +5236,23 @@ the user a message to return to their device. Meanwhile, the client instance periodically polls the AS every 60 seconds at the continuation URL. The client instance signs the request using the same key and method that it did in the first request. POST /continue/VGJKPTKC50 HTTP/1.1 Host: server.example.com Authorization: GNAP 80UPRY5NM33OMUKMKSKU - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... The AS retrieves the pending request based on the handle and 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 can continue to call after another 60 second timeout. HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store @@ -5423,30 +5258,31 @@ { "continue": { "access_token": { "value": "G7YQT4KQQ5TZY9SLSS5E" }, "uri": "https://server.example.com/continue/ATWHO4Q1WV", "wait": 60 } } - Note that the continuation URL and access token have been rotated since they were used by the client instance to make this call. The client instance polls the continuation URL after a 60 second timeout using this new information. POST /continue/ATWHO4Q1WV HTTP/1.1 Host: server.example.com 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 token, determines that it has been approved, and issues an access token for the client to use at the RS. HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store { @@ -5508,21 +5344,23 @@ 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 asynchronously reach out to the RO for approval in this scenario. The client instance starts the request at the AS by requesting a set of resources. The client instance also identifies a particular user. POST /tx HTTP/1.1 Host: server.example.com Content-Type: application/json - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "access_token": { "access": [ { "type": "photo-api", "actions": [ "read", "write", "dolphin" @@ -5579,21 +5417,22 @@ 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 to for the specified account. Meanwhile, the client instance periodically polls the AS every 60 seconds at the continuation URL. POST /continue HTTP/1.1 Host: server.example.com Authorization: GNAP 80UPRY5NM33OMUKMKSKU - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... The AS retrieves the pending request based on the handle and 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 can continue to call after another 60 second timeout. HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store @@ -5607,21 +5446,22 @@ } } Note that the continuation handle has been rotated since it was used by the client instance to make this call. The client instance polls the continuation URL after a 60 second timeout using the new handle. POST /continue HTTP/1.1 Host: server.example.com Authorization: GNAP BI9QNW6V9W3XFJK4R02D - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... The AS retrieves the pending request based on the handle and determines that it has been approved and it issues an access token. HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store { "access_token": { @@ -5654,21 +5494,23 @@ &response_type=code &state=123455 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 the OAuth 2.0 values in the appropriate places. POST /tx HTTP/1.1 Host: server.example.com Content-Type: application/json - Detached-JWS: ejy0... + Signature-Input: sig1=... + Signature: sig1=... + Digest: sha256=... { "access_token": { "access": [ "read", "write", "dolphin" ], "flags": [ "bearer" ] }, "client": "7C7C4AZ9KHRS6X63AJAO", "interact": {