Draft: draft-ietf-gnap-core-protocol

Commentary: Deploy preview for gnap - core - protocol - editors - draft ready ! Built with commit https://deploy - preview-162 - -gnap - core - protocol - editors- 
 So I was starting to have a look at rotation / revocation issues ( keys or tokens ) , as we have many open issues that relate to that Interesting insight from DIF KERI ( Universal Identifier Theory paper ) " The term revocation has two completely different meanings in the identity space . In key management one may speak of revoking keys . With statement issuance , authorization issuance , or credential issuance , one may speak of revoking an authorization statement , a token , or a credential . This becomes confusing when the act of revoking keys also implicitly revokes the authorization of statements signed with those keys . " and "  terminology usually avoids that confusion between rotation and revocation because a key rotation operation is the equivalent of a key revocation operation followed by a key replacement operation . So one operation , rotate , is implemented instead of two operations ( revoke and replace ) . " 
 Related question : what is persistent ( drawback , need to store that info somewhere , safely ) ? what is ephemeral ? what 's the lifecycle of related objects ? And more specifically : every new request needs to provide a key -don't need long term persistance for that , we simply need to handle key rotations during a single request ( as described in issue ) objets derived from some underlying key however ( including bound tokens ) might be more tricky ( ex ) . Do we need some kind of registry to keep track of the changes over time , to keep them alive even if the key changes ? Or do we just consider that they get revoked ? ( and what happens if you fall into that case at some point , what 's your next action ? ) 
 This is already managed by section 7.2 " 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 ) " 
 The current interaction modes listed are : , , , , and . There are three different types of flags here : how the client can tell the user how to interact with the AS ( , , ) how the client can handle a response from the AS ( ) hints to the AS ( ) We should consider whether it makes sense to group these so that future extensions do n’t run the risk of conflicts and so that the purpose of each is clearer to developers . For example ( names TBD ): ( See PR ) 
 +1 This brings clarity . 
 I like this approach , and it 's largely equivalent to what we have right now ( but with more clarity ) . I think it could even be combined with the bundling concept in if we wanted to . 
 Polymorphism question ... are we going for the style where if an array has only one value it 's also okay to send that one value itself ? e.g. can also be represented by It 's less important for string values , but forcing everything into an array starts to look awkward when values are objects : vs 
 I made an initial attempt at this in PR , however depending on the polymorphism question above I 'll need to clean it up still . 
 My personal view is that the polymorphism should always be clearly unambiguous for every field . In other words , if it 's an object it always means the same thing , an array always means the same thing , etc . If this means that a field is either an object or an array of those objects , then we could support that . However , I 'd argue that we should n't have this kind of optimization when there 's no semantic difference . That is to say , when there 's an array of one object it should still always been an array unless we have a compelling reason to define both formats . For access tokens , it 's semantically different to ask for a single vs. multiple access tokens , so they use this object vs. array - of - object structure mentioned here . But what 's proposed here looks like a simple optimization . While I personally think that 's sensible to do , I think we can and should address that optimization separately . This is the approach I took with . 
 I guess this question is actually slightly more complex than whether this is a simple optimization of a single - value array . Where it gets tricky is when we want to use multiple of these modes combined . Combining string values is easy : Combining objects can be done in two ways : It 's a difference of " object with keys " vs " array of objects " I guess . The downside of the " object with keys " approach is then simple string values are n't really possible without doing the awkward boolean true thing , whereas an " array of objects " could also just as easily be an " array of objects and strings " . This is mostly a stylistic question at this point , but I do think we should write up some guidance around this so that we have something to reference when we have these questions in the future . 
 Good questions on polymorphism . That 's pretty similar to what Justin suggested , I would start with the syntax that we think is most consistent and then see if compact alternatives make sense . But I liked lisp . So I may not be acting normally :-)  aside I think it 's hard to tell for sure right now . 
 I do n't think it makes sense to have multiple modes for " finish " . How would the AS know which one(s ) to fire ? 
 That 's an interesting point that I had n't seen mentioned before . I was thinking of the exchange as the client saying " here are all the things I can do " and the AS picking the ones of the list that it supports . So in some cases one AS may not support some completion modes that another AS does , where a client can support all . 
 The model I 'm in favor of is the client instance providing multiple ways to get started and one way to get back . Letting the AS pick the return leaves the client in charge of listening to different callbacks , which are going to have different security properties . This seems like it 's going to open the door to new and fun attack vectors -- like convincing a client to go poll by posting to a static URL when it should be getting a bound callback parameter on a dynamic URL . This is a very different situation than the AS listening for multiple interaction points , though -- the AS is in more control and the security stakes are known to be high , so it should be more aware of the process . If the client has multiple ways to get back , the AS would likely want to offer different experiences for each , based on those expectations . This is where the multiple - mode bundling idea of comes into play , in which case we 'd look at having the upper - level " interact " structure possibly be multiple , in that case . 
 I also think a single finish is best . The only case I 'd imagine several possibilities is if the client can specify the rules to help decide , but it 's probably over complex ( I do n't see a practical example of where that would be useful ) . So aligned with previous comment . One additional ( maybe unrelated ) question is whether the continuation could allow to chain successive interactions or whether everything is supposed to be handled in one go . Successive interaction could be useful if you 'd want to implement a process with several successive URIs . Maybe that 's dumb but I had the demand from a customer just yesterday ( did n't think much about it yet ) . 
 Okay , if a single finish is the plan we should make sure these motivations are clarified in the spec too ! With the current syntax ( before this PR ) it 's possible for the syntax to allow multiple finish options . With the new syntax we can at least enforce a single finish option . 
 Apologies for any newbie mistakes , but this makes me wonder how we handle the response to an authorization request . In many real - world cases , especially healthcare , the authorization is requested by a client as user agent of the RQ but the response is presented to the RS by another client such as the institutional system of the RQ 's employer that may be under the control of another RQ or an institution . This delegation of the authorization from one client to another may be out of scope for GNAP but I am worried about how the RS will handle this distinction in cases where they want to minimize their risk . 
 So I 'm wondering if we should make " finish " just be the internal structure of what 's in " callback " today : This would keep the " one way to finish " aspect , but would n't rule out someone defining some sort of hybrid finish if something like that would exist . 
 Actually that solves as well by dropping the name " callback " entirely . I think this is a good plan . I 'll update the PR . 
 Actually this has some pretty significant implications elsewhere in the spec . Right now there 's a lot of references to the " callback " mode , e.g. Dropping that from the object means we do n't really have a way to refer to the " callback " mode anymore . I think I 'm okay with this , since we can still refer to the " redirect " or " push " modes defined in the spec . e.g : changes to If we agree I 'll keep going with the changes here . 
 A more significant change is the response from the AS , in does n't make sense anymore , so probably that would have to change to : and I do like that it 's removing one layer of abstraction though and being more direct . 
 Those are still separate " interaction finish methods " that would need to be defined separately , and so I think it should be fine to swap the references in - place . I think the return for this could now actually be something like : Or we could keep it collapsed , swapping for like with the request : I 'm not convinced having different member names for different finish methods at the top level of the object is a good idea , from a namespace cleanliness perspective -- extensions are going to be able to define both start and finish methods , and they 'll need to somehow live in the response together . Maybe like with the discussion above we just keep the " verbose " form and figure out if an optimization makes sense later ? I could go either way , personally . 
 in your use case , the end - user and resource owner are separate , so the client is n't handling the " start " of the interaction process . The client can still be notified of when it 's finished in a secure fashion , which is what the " pushback " method is good for . Or the client can just poll , waiting for it to be approved by someone , so it would n't need to know externally when the authorization is completed . 
 Okay that makes sense . I do n't think the client benefits from having the method confirmed in the response so I 'll start with the simpler version that 's more inline with the current one anyway : 
 Alright , that was quite a bit of surgery but I do think this cleans things up nicely now ! Current draft can be viewed here : https://deploy - preview-164 - -gnap - core - protocol - editors- 
 I 'm playing catch - up here so please bear with me . Yes , the end - user and resource owner are separate . In this use - case the resource owner 's client is irrelevant because they have delegated authority to respond to requests to an authorization server . In this use - case the end user is using two different clients as part of the interaction process . One client is a true user agent , the other client is an agent of some other entity . The client that interacts with the authorization server is logically and maybe legally separate from the client that interacts with the resource server . Optionally , the end - user that began the interaction with the authorization server may delegate their authorization to another end - user that will actually access the resource with a different client . Finally , in this use - case , the resource server may seek signed software statements from the client presenting the authorization . Those software statements may or may not also be shared with the authorization server as part of the interaction . I do n't understand your response about client polling because I am not concerned about that . If this use - case is already handled in the spec , please point me to the relevant sections . 
 Justin might correct if I 'm wrong , but seems to me that this use case is currently not covered . As far as I understand it however , it would be possible I think through biscuit tokens ( + ) , but the delegation between clients is not covered through the protocol . 
 I do n't expect the delegation between clients to be covered through protocol , just possible . The issue of delegation among end - users has been a hot topic in credential and storage W3C workgroups . Here , for example is with over 100 messages . There are many others and the issue is far from resolved . My goal is harmony between W3C data models and GNAP . I 've created a very concise model for that may be helpful here as well . The use - case we 're discussing here is on . In due course , we may choose to consider harmony on the other use cases as well , such as authentication . I know precious little cryptography . If we used biscuits , would GNAP adopt them for everything or would the option be a request on the part of the requesting party ? 
 will look into your docs . GNAP is agnostic on the token format , of course the default being jwt . Biscuits are indeed based on fancy crypto 
 Is there a chance that the interaction could panic / fail with an unrecoverable error that requires to stop the flow ? For instance : reach a timeout ( the RO just went for a walk ) the client developer made a mistake in the start section , his device is unable to redirect to a proper display 
 Regarding the wording : we currently use " completed interaction " in the text . Maybe people could wonder if that 's the same as " finish " ? 
 I believe your concerns would be better managed in dedicated issues . I 've looked at your use case ( thanks for the slides , that 's clear ) . In my view , the delegation that you 're describing with different clients should be managed through tokens that are able to manage that complexity , such as biscuits . See I 've also created a new issue for the distinct case when end - user ! = RO , see Please feel free to comment on those issues directly . 
 See PR 
 PR has been merged 
 Rotating the Access Token :  's note : We could also use different verbs to signal whether or not the old token should be kept around or not , instead of using a token flag to do this . 
 Keep " MUST if possible " here . If you want two access tokens , use the grant API not the token rotation API . The rotation mechanism should be for getting a new value for an existing token and replacing it , not for minting entirely new separate tokens ( which is what the grant continuation / update API is for ) . We need to keep " if possible " for the case of using stateless tokens ( fully self - contained JWTs ) , and add a discussion on when it might not be possible . 
 Modifying an Existing Request :  's note : This might be subject to the " multi_token " flag , but since we 're creating a NEW access token and not rotating an existing one , this seems to be a different use case . There is a solid argument to be made for always revoking old access tokens here , but we need more discussion on the boundaries for such a requirement . If they stick around , it does make a " read " request weird because now we 've got multiple access tokens sticking around associated with a grant request and no good place to put them . 
 I do n't think we should put a strict requirement on revoking old access tokens , since it may be difficult or impossible in some implementations . At most this could be a " SHOULD " or " RECOMMENDED " . 
 Currently , access tokens are requested using the parameter , but there might be different things to affect the resulting access tokens , such as the token flags in 2.1.4 . An alternative would be to allow tokens to be requested using an object syntax where is one of the elements : In this example , the field mimics what the field of the token response does , here indicating that the token should be bound to the client instance 's own key . The field takes the place of the flag ( and ultimately we would n't need the token flags structure ) . The field is a client - supplied token label , which would be required if the client requested multiple tokens , such as something like this : This would take the place of the multiple - token syntax map used in § 2.1.3 today . 
 This is a possible way to address and 
 Signaling Token Behavior :  's note : While these reference values are " reserved " , the ultimate decider for what a reference means is the AS , which means an AS could arguably decide that one of these values means something else . Also , this kind of reservation potentially steps on API namespaces , which OAuth 2 is careful not to do but common extensions like OIDC do with their own scope definitions . However , in OIDC , several " scope " values have behavior similar to what 's defined here , particularly " openid " turns on ID tokens in the response and " offlineaccess " signals for the return of a refresh token , and these can be used outside of OpenID Connect itself . However , to keep these flags out of the general API namespace , we could use a different syntax for sending them . In particular , they could be defined under a GNAP - specific " type " object , where all the flags are fields on the object . Alternatively , all the flags could be sent in an array separate from the rest of the request . This whole thing might also belong in an extension , as it 's advanced behavior signaling for very specific cases . However , it seems other extensions would be likely to extend this kind of thing , like OIDC did with " offlineaccess " . 
 This potential namespace conflict issue stood out to me as well and I think it would be better to solve earlier than later . Especially if this kind of thing does end up in an extension , it makes sense to have a way for extensions to define additional flags in a way that wo n’t conflict with other defined resource references . 
 Signaling Token Behavior :  's note : This functionality is controversial at best as it requires significantly more complexity on the client in order to solve one class of AS / RS deployment choices . 
 Yaron : Why is key binding of the access token even optional ?  : Because people still want to use bearer tokens as an option . I think we can make bound tokens first class citizens in GNAP , and that ’s a large reason behind having consistent key binding approaches instead of having them separated out ( section 8) . I think we can even make the “ default ” having the token bound to the RC ’s presented key ( and therefore make “ unbound token ” a flag instead ) , but I do n’t think there would be support in the community for removing bearer tokens entirely . Yaron : So let 's pick one method , and make it mandatory - to - implement and " default " . Terminology : I think the common usage is to talk about " token binding ( to a key ) " rather than " key binding ( to what ? ) " . 
 I agree that there should be one default method , defining 6 methods seems over the top ? I had n't realised that this draft proposes  with an additional claim for the digest - we are working on something similar in the FAPI WG at the moment . Mutual TLS is hard to require as mandatory to implement as it mixes application and transport layer concerns , so I would suggest or be the default as they can be implemented purely at the application layer and use standard JWTs . 
 Related : tokens being bound to the client 's key are made the default mode in , bearer tokens are still possible by passing in a flag . 
 Bound tokens are the default throughout , MTI considerations tracked under 
 Yaron ( referring to ): I suggest to extend the editor 's note to clarify what is the use case , so that the group can decide whether split tokens are indeed necessary .  : I think we should have a more detailed conversation about this potential feature than an editor ’s note could reasonably get into . There are a number of large items ( splitting access tokens , directing access tokens to specific portions of API or RS ’s , among others ) that I think will be big conversations for the WG , and all the context of these do n’t necessarily need to be documented inside the notes in the document itself . But for discussion and context , this feature was proposed to deal with cases where the AS might decide to issue several access tokens in any case where the client requested one , because the AS wants to have restricted audiences for individual access tokens but the client does n’t know about the audiences ahead of time . I agree that it ’s a compelling use case , and it puts security of the protected domains in the hands of the AS where it belongs , but it would require a client to be smart enough to know what to do with these tokens downstream , and if OAuth has taught us anything it ’s that we ca n’t rely on client software to be smart about most anything . :) 
 See also 
 I always considered the " split_token " functionality as a nice addition to the protocol . It gets available for the client when it explicitly requests it + the AS can issue multiple ATs . Among other described scenarios above , I had in mind this particular one ; let 's say there are two almost identical RSs , the difference is only in the way how much you need to pay to use them , for example , our client wants to store video recordings , RS2 works a bit faster and guarantees more protection against data loss . At the same time , RS1 and RS2 belong to different organizations that have nothing in common + the client knows nothing about RS1 and RS2 in advance . 
 For this scenario , you 'd also need a way to explicitly direct the client instance to either RS1 or RS2 along with the token . There 's nothing in the protocol that does that today ( see ) . Both of these could be handled as an extension . The current view of the editors is that this is a " nice to have " , which is n't enough for it to be in core , especially not without implementation experience . 
 I agree that there 's nothing in the protocol that does that as of today . I was thinking about why the AS can not pass a piece of the information along with an AT or ATs ( for the split token feature ) it issues . This is what would happen in my implementation of the AS and the client library ( SDK ) . This piece of information is nothing more than a JSON object and it 's assumed that the AS and the client both know how to deal with it ( there is already a bright example of the information we pass in a similar fashion , it 's " expires_in " parameter ) . I also assume that might have something like that . I would n't say my implementation counts as it 's a POC . Please , note that RS1 and RS2 are n't mutually exclusive for the client in my example . The client may use them both at the same time . The client wants to store the video recordings and these RSs might do something meaningful with them even say in real - time . It 's up to you to decide what and what not to have at the very core of the protocol . The split - token feature and seem to be controversial topics that might bring lots of complexity . 
 Yaron : why are flags represented as resources ? The answer , " this is how OAuth 2 does it " is not great .  : The idea is that these are items that alter what the access token that ’s being requested in the “ resources ” section . It is a sensible way to hang things together since everything in the array ties to a specific access token . This was a proposed design compromise , and if these flags can fit elsewhere then we can do that . Yaron : this still does n't explain why we do n't have a object ( or array ) , parallel to the array . 
 I think this begs the question of whether we 'd like a higher - level construct per access token . Right now we only have the array but perhaps the request could incorporate a more descriptive request object that includes the array and possibly other items , like flags . 
 Makes sense . But I think this depends on whether and how we want to support the " multiple access tokens " feature . I suggest to resolve that discussion first . 
 Right , this is definitely related to the syntax discussed in . One potential way to handle it would be for a single request to be an object with a array , but a multiple access token request as an array of single access token requests . The problem is labeling the request in such a way as to ensure the client knows what to do with the resulting tokens , but that can be discussed in . 
 Yaron : an array for a single AT vs. an object for multiple ATs ? This is extremely non - intuitive and probably ugly to code . Also , why should ( multiple ) tokens be named if a single token does n't have to , why not list them in an array instead ?  : I agree that it looks a little odd at first glance , but I ’ve coded this in a few languages now and on the request side ( this section ) it is really clear what you ’re doing . I think it might be helpful to build up from the parts of this section of the request , which will show the history and decision process that got us to the syntax that ’s there today . Obviously , this is n’t a statement that it needs to stay this way , but I hope that this will help bring to light the reasoning behind what ’s there now so that it can be explained , refined , or updated as needed . At the lowest level , we ’ve got the dimensions for access . OAuth 2 showed us that “ scope ” was a useful way for a client to indicate what it wants , but we ’ve found that API designers have used scope to talk about many different dimensions of access , all rolled into different scope values . We are now being explicit about those dimensions , and trying to make those dimensions orthogonal to each other . There is some small amount of fuzziness and potential overlap of interpretation , and ultimately these are all up to the AS / RS ( and the API designer , really ) to define : type : “ the kind of API I want to call ” , like OIDC UserInfo or FHIR Medical Record datatypes : “ the kind of data I want to use at the API ” , like email addresses or office visits actions : “ the kind of actions I want to do on the API ” , like read , or write , or make the robot move locations : “ the RSs I want to call the API on ” , like the URL of the UserInfo Endpoint or a URI for a specific document server cluster identifier : “ the entity I want to do these actions on ” , like the medical record ID or bank account number These are all strings or arrays of strings , and they ’re meant to be very specific to the requested access to the API . Specific APIs are likely to add their own dimensions as well , which can be pretty much anything so long as the RS can interpret the token that it represents . This is why we have the “ type ” field , which gives us a way to namespace the dimensions . But these dimensions do n’t live alone : I ’m not going to just ask for “ read ” or just “ medical record ” , I probably want to ask for “ read the medical record ” . With scopes , we were forced to just put them all in a bucket and define awkward semantics for combining them , and then watch things go awry as an AS protected different APIs with different interpretations of , for example , “ email ” as a scope . So with GNAP , we ’ve got a way to combine them into single objects . That lets us create combinations like “ read the medical record ” by combining the “ type ” and “ actions ” fields into a single object . The “ pass by reference ” feature allows us to send a simple string value that is interpreted as if it were one of the objects . So maybe there ’s a “ fhir - read ” value that means “ read all available sections of the fhir medical record of the current user ” . You can think of it like a pre - computed object where the client does n’t have to specify all the details — and in that way it works almost just like a scope value would . But what if I want read access to the medical history record but ALSO want update access to the demographic information ? We ca n’t just throw it all onto the same object because there are two very distinct requests , but one access token can reasonably encompass both . So in GNAP we ’ve got an array of objects that allows us to combine these multidimensional requests and have them all apply to a single access token . Since any of these objects could potentially be replaced by a string , this array could have a combination of strings or objects , but each item in the array represents the same kind of multi - dimensional request . The “ scope ” field in OAuth 2 is semantically an array ( even though it ’s formatted as a space - separated list of space - free ascii strings ) for exactly this reason : I should be able to ask for multiple scopes at the same time . The resulting access token is for the total of everything in the array ( that ’s granted — of course any of this can be changed by the AS and RO ) . So an access token always represents an array of requested access rights , each access right is an object that describes what ’s being requested across several dimensions which are properties of that object in their own syntax . An access token is a combined collection of access rights , so requesting an access token requires the structure of an array . And so far , this is inline ( by design ) with what ’s in OAuth 2 RAR : And that brings us to multiple access tokens : Multiple access tokens are requested by sending an object which uses labels to mark individual single access token requests , which as we just saw is an array — so it ’s an object whose values are all arrays , but specifically arrays that are defined to ask for a single access token . Why put the labels on these requests ? Multiple access tokens need to have names ( or labels ) so that the client can tell : which : of its access requests each token maps to . Otherwise , how can a client know which set of resources it ’s supposed to use each token with ? The “ locations ” field ( discussed more below ) is for identifying sets of resources , and so that field is not likely to be the exact set of URLs that the client can use the token at . And it ’s also not guaranteed that all APIs will use “ locations ” in a way that ’s meaningful to a client — what if the client wants “ read ” and “ write ” access at the same API with different tokens ? The “ read ” token could be long - lived but the “ write ” token short lived , for security purposes , but the “ locations ” would be the same . Additionally , the “ read ” could be limited to GET requests and the “ write ” limited to “ POST ” requests , neither of which is really expressed in “ locations ” . If the RC is going to ask for different tokens in a single request , it needs to have a way to differentiate the portions of the response from each other . There are some different syntaxes we could use to make parts of this work , but these choices tend to have other follow - on effects . Here are a few that I ’ve cycled through in the design of the current proposal : We could ask for multiple access tokens this by having a “ label ” field inside the request for a single access token and then sending an array of single access token request ( so an array of arrays ) , but then you need to answer the question of where in the request to put the label . Should it go in the array like the proposed “ token flags ” ? Should it go inside one of the objects in the array ? But if it does , what would it mean for multiple objects in the array to have a “ label ” value ? Additionally , we ’d need to detect at the top level whether we had an array of arrays or an array of objects and strings — doable , but more prone to weird error cases . ( What if an RC sends an array with one array and one object ? We need to detect that now and might end up down the wrong code path before we do , with a naive parser anyway . ) We could simply require all tokens to be labeled at all times , but I would argue that the overwhelmingly common use case of a single access token does n’t need that kind of overhead because there ’s only one set of requested items that the RC is asking for . We could define single access tokens as an object , with multiple aspects . This would potentially let us hang additional fields off of the access token request alongside the resource list , but it would also mean that we ’d have a degenerate case where you ’re defining an object with one member , whose value is always an array . In other words , this is exactly what the JSON Web Key Set format does , which I ’ve always found clunky . The top level object does n’t add anything in the JWKS case , and I ’m not seeing how it would add anything here . On the other hand , this would let us use an object for a single access token and potentially an array for multiple access tokens , but at some cost to the complexity at the layers below that . None of those ideas lead to a better syntax across the different uses cases , or that optimize for simplicity in the common use cases . All that is to say that I currently think that what we have is the simplest and cleanest approach that I ’ve seen so far , and I would really love to see if there are any alternatives that offer this same kind of power and clarity when exercised the same . I would love to see some fresh ideas on different ways to approach this . Yaron : wow , that was a long read , thank you ! IMHO an array ( which in the common case has a single element ) is just fine . I hate making up names ( " labels " ) for no good reason . 
 Looks good to me!Seems fine to me , thanks . I copy the answers to my questions , as I think they 're useful to understand some of the choices . does it mean we make token binding the default behaviour ? ( if so we should explicit why this choice is made ) Yes , that is the idea . One of the goals of GNAP is to have it more secure than  by default , and having bound tokens be first class and relatively simple ( ie , it ’s just token presentation and key proof combined , and you need to do key proof anyway ) is in line with that goal . I do n't think there 's a need to be more explicit in the spec itself but at least it clarifies the intent . I 'm also wondering whether the split flag is to be provided on the client side . Do we think there could be reasons for clients not to be able to deal with that?I would have expected that this is more something driven by the AS , based on policies the client might want to be able to be aware of ( through OPTION ) . Splitting tokens is an advanced piece of functionality that drastically increases the complexity on the client side , and so I would only want this to be an option if the client chooses it . My design philosophy around things like this in the protocol is that a simple client should be able to implement a subset of the protocol ’s syntax and still function just fine , in a predictable and secure fashion .
Paragraph (version A):
The AS determines which RO to contact based on the request in (1),
through a combination of the request-user, the request-resource,
and other policy information.  The AS contacts the RO and
authenticates them.
Paragraph (version B):
The AS determines which RO to contact based on the request in (1),
through a combination of the request-user, the request-token, and
other policy information.  The AS contacts the RO and
authenticates them.
Paragraph (version A):
Describes the rights that the client instance is requesting for
one or more access tokens to be used at RS's.
Paragraph (version B):
Describes the rights and properties associated with the requested
access token.
Paragraph (version A):
If the client instance is requesting one or more access tokens for
the purpose of accessing an API, the client instance MUST include a
"resources" field.  This field MUST be an array (for a request-
resource-single) or an object (for request-resource-multiple), as
described in the following sections.
Paragraph (version A):
When requesting an access token, the client instance MUST send a
"resources" field containing a JSON array.  The elements of the JSON
array represent rights of access that the client instance is
requesting in the access token.  The requested access is the union of
all elements within the array.
Paragraph (version A):
The client instance declares what access it wants to associate with
the resulting access token using objects that describe multiple
dimensions of access.  Each object contains a "type" property that
determines the type of API that the client instance is calling.
Paragraph (version A):
The value of this field is under the control of the AS.  This field
MUST be compared using an exact byte match of the string value
against known types by the AS.  The AS MUST ensure that there is no
collision between different authorization data types that it
supports.  The AS MUST NOT do any collation or normalization of data
types during comparison.  It is RECOMMENDED that designers of
general-purpose APIs use a URI for this field to avoid collisions
between multiple API types protected by a single AS.
Paragraph (version A):
The following non-normative example is asking for 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.
Paragraph (version A):
Instead of sending an request-resource-single, a client instance MAY
send a string known to the AS or RS representing the access being
requested.  Each string SHOULD correspond to a specific expanded
object representation at the AS.
Paragraph (version A):
A single "resources" array MAY include both object-type and string-
type resource items.  In this non-normative example, the client
instance is requesting access to a "photo-api" and "financial-
transaction" API type as well as the reference values of "read",
"dolphin-metadata", and "some other thing".
Paragraph (version A):
When requesting multiple access tokens, the resources field is a JSON
object.  The names of the JSON object fields are token identifiers
chosen by the client instance, and MAY be any valid string.  The
values of the JSON object fields are JSON arrays representing a
single access token request, as specified in request-resource-single.
Paragraph (version A):
Any approved access requests are returned in the response-token-
multiple structure using the token identifiers in the request.
Paragraph (version A):
While the AS is ultimately in control of how tokens are returned and
bound to the client instance, sometimes the client instance has
context about what it can support that can affect the AS's response.
This specification defines several flags that are passed as request-
resource-reference.
Paragraph (version A):
Each flag applies only to the single resource request in which it
appears.
Paragraph (version A):
Support of all flags is optional, such as any other resource
reference value.
Paragraph (version A):
The client instance wishes to support multiple simultaneous access
tokens through the token rotation process.  When the client
instance rotate-access-token, the AS does not invalidate the
previous access token.  The old access token continues to remain
valid until such time as it expires or is revoked through other
means.
Paragraph (version A):
The AS MUST respond with any applied flags in the response-token
"resources" section.
Paragraph (version A):
In this non-normative example, the requested access token is to be
bound to the client instance's key and should be kept during
rotation.
Paragraph (version A):
Additional flags can be registered in IANA.
Paragraph (version B):
If the client instance is requesting one or more access tokens for
the purpose of accessing an API, the client instance MUST include an
"access_token" field.  This field MUST be an object (for a request-
token-single) or an array of these objects (for request-token-
multiple), as described in the following sections.
Paragraph (version B):
To request a single access token, the client instance sends an
"acccess_token" object composed of the following fields.
Paragraph (version B):
Describes the rights that the client instance is requesting for
one or more access tokens to be used at RS's.  This field is
REQUIRED.
Paragraph (version B):
A unique name chosen by the client instance to refer to the
resulting access token.  The value of this field is opaque to the
AS.  If this field is included in the request, the AS MUST include
the same label in the response-token.  This field is REQUIRED if
used as part of a request-token-multiple, and is OPTIONAL
otherwise.
Paragraph (version B):
A set of flags that indicate desired attributes or behavior to be
attached to the access token by the AS.  This field is OPTIONAL.
Paragraph (version B):
Flag values MUST NOT be included more than once.
Paragraph (version B):
Additional flags can be defined by extensions using IANA.
Paragraph (version B):
In the following example, the client instance is requesting access to
a complex resource described by a pair of access request object.
Paragraph (version B):
If access is approved, the resulting access token is valid for the
described resource and is bound to the client instance's key (or its
most recent rotation).  The token is labeled "token1-23" and could be
split into multiple access tokens by the AS, if the AS chooses.  The
token response structure is described in response-token-single.
Paragraph (version B):
To request multiple access tokens to be returned in a single
response, the client instance sends an array of objects as the value
of the "access_token" parameter.  Each object MUST conform to the
request format for a single access token request, as specified in
request-token-single.  Additionally, each object in the array MUST
include the "label" field, and all values of these fields MUST be
unique within the request.  If the client instance does not include a
"label" value for any entry in the array, or the values of the
"label" field are not unique within the array, the AS MUST return an
error.
Paragraph (version B):
All approved access requests are returned in the response-token-
multiple structure using the values of the "label" fields in the
request.
Paragraph (version A):
A single access token that the client instance can use to call the
RS on behalf of the RO.
Paragraph (version A):
Multiple named access tokens that the client instance can use to
call the RS on behalf of the RO.
Paragraph (version B):
A single access token or set of access tokens that the client
instance can use to call the RS on behalf of the RO.
Paragraph (version A):
If the AS has successfully granted one or more access tokens to the
client instance, the AS responds with either the "access_token" or
the "multiple_access_token" field.  The AS MUST NOT respond with both
the "access_token" and "multiple_access_token" fields.
Paragraph (version B):
If the AS has successfully granted one or more access tokens to the
client instance, the AS responds with the "access_token" field.  This
field contains either a single access token as described in response-
token-single or an array of access tokens as described in response-
token-multiple.
Paragraph (version B):
The client instance uses any access tokens in this response to call
the RS as described in use-access-token.
Paragraph (version B):
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
request-client 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.
Paragraph (version B):
REQUIRED for multiple access tokens, OPTIONAL for single access
token.  The value of the "label" the client instance provided in
the associated request-token, 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".
Paragraph (version A):
RECOMMENDED.  A description of the rights associated with this
access token, as defined in request-resource-single.  If included,
this MUST reflect the rights associated with the issued access
token.  These rights MAY vary from what was requested by the
client instance.
Paragraph (version B):
RECOMMENDED.  A description of the rights associated with this
access token, as defined in resource-access-rights.  If included,
this MUST reflect the rights associated with the issued access
token.  These rights MAY vary from what was requested by the
client instance.
Paragraph (version A):
REQUIRED.  The key that the token is bound to.  If the boolean
value "true" is used, the token is bound to the request-client in
its request for access.  If the boolean value "false" is used, the
token is a bearer token with no key bound to it.  Otherwise, the
key MUST be an object or string in a format described in key-
format, describing a public key to which the client instance can
use the associated private key.  The client instance MUST be able
to dereference or process the key information in order to be able
to sign the request.
Paragraph (version A):
The following non-normative example shows a single bearer token with
a management URL that has access to three described resources.
Paragraph (version A):
The following non-normative example shows a single access token bound
to the client instance's key, which was presented using the detached-
jws binding method.
Paragraph (version A):
If the client instance request-resource-multiple, the AS MUST NOT
respond with a single access token structure unless the client
instance sends the "split_token" flag as described in request-
resource-flag.
Paragraph (version A):
If the client instance has requested multiple access tokens and the
AS has granted at least one of them, the AS responds with the
"multiple_access_tokens" field.  The value of this field is a JSON
object, and the property names correspond to the token identifiers
chosen by the client instance in the request-resource-multiple.  The
values of the properties of this object are access tokens as
described in response-token-single.
Paragraph (version A):
Each access token corresponds to the named resources arrays in the
client instance's request-resource-multiple.
Paragraph (version B):
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 key-format, describing a public
key to which the client instance can use the associated private
key.  The client instance MUST be able to dereference or process
the key information in order to be able to sign the request.
Paragraph (version B):
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 rotate-access-token or the
underlying grant request has been continue-modify, 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.
Paragraph (version B):
OPTIONAL.  Flag indicating that this token was generated by
issuing multiple access tokens in response to one of the client
instance's request-token objects.  This behavior MUST NOT be used
unless the client instance has specifically requested it by use of
the "split" flag.
Paragraph (version B):
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).
Paragraph (version B):
The following non-normative example shows a single bearer access
token with access to two described resources.
Paragraph (version B):
If the client instance request-token-single, the AS MUST NOT respond
with the multiple access token structure unless the client instance
sends the "split" flag as described in request-token-single.
Paragraph (version B):
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 response-
token-single.  Each object MUST have a unique "label" field,
corresponding to the token labels chosen by the client instance in
the request-token-multiple.
Paragraph (version B):
Each access token corresponds to one of the objects in the
"access_token" array of the client instance's request-token-multiple.
Paragraph (version A):
If the client instance request-resource-single, the AS MUST NOT
respond with the multiple access token structure unless the client
instance sends the "split_token" flag as described in request-
resource-flag.
Paragraph (version A):
Each access token MAY have different proofing mechanisms.  If
management is allowed, each access token SHOULD have different
management URIs.
Paragraph (version B):
If the client instance request-token-multiple, 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.
Paragraph (version B):
Each access token MAY be bound to different keys with different
proofing mechanisms.
Paragraph (version B):
If token-management is allowed, each access token SHOULD have
different "manage" URIs.
Paragraph (version A):
Some references, such as for the request-instance or the request-
resource-reference, can be managed statically through an admin
console or developer portal provided by the AS or RS.  The developer
of the client software can include these values in their code for a
more efficient and compact request.
Paragraph (version B):
Some references, such as for the request-instance or the resource-
access-reference, can be managed statically through an admin console
or developer portal provided by the AS or RS.  The developer of the
client software can include these values in their code for a more
efficient and compact request.
Paragraph (version A):
The AS replaces the previous "resources" from the first request,
allowing the AS to determine if any previously-granted consent
already applies.  In this case, the AS would likely determine that
reducing the breadth of the requested access means that new access
tokens can be issued to the client instance.  The AS would likely
revoke previously-issued access tokens that had the greater access
rights associated with them.
Paragraph (version B):
The AS replaces the previous "access" from the first request,
allowing the AS to determine if any previously-granted consent
already applies.  In this case, the AS would likely determine that
reducing the breadth of the requested access means that new access
tokens can be issued to the client instance.  The AS would likely
revoke previously-issued access tokens that had the greater access
rights associated with them, unless they had been issued with the
"durable" flag.
Paragraph (version A):
The header of the JWS MUST contain the "kid" field of the key bound
to this client instance for this request.  The JWS header MUST
contain an "alg" field appropriate for the key identified by kid and
MUST NOT be "none".
Paragraph (version B):
The header of the JWS MUST contain the "kid" field of the key bound
to this client instance for this request.  The JWS header MUST
contain an "alg" field appropriate for the key identified by "kid"
and MUST NOT be "none".
Paragraph (version B):
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 request-token and when an response-
token.
Paragraph (version B):
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
access token.  The resulting access is the union of all elements
within the array.
Paragraph (version B):
The access associated with the access token is described using
objects that each contain multiple dimensions of access.  Each object
contains a REQUIRED "type" property that determines the type of API
that the token is used for.
Paragraph (version B):
The value of the "type" field is under the control of the AS.  This
field MUST be compared using an exact byte match of the string value
against known types by the AS.  The AS MUST ensure that there is no
collision between different authorization data types that it
supports.  The AS MUST NOT do any collation or normalization of data
types during comparison.  It is RECOMMENDED that designers of
general-purpose APIs use a URI for this field to avoid collisions
between multiple API types protected by a single AS.
Paragraph (version B):
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.
Paragraph (version B):
Instead of sending an resource-access-rights, access rights MAY be
communicated as a string known to the AS or RS representing the
access being requested.  Each string SHOULD correspond to a specific
expanded object representation at the AS.
Paragraph (version B):
A single "access" array MAY include both object-type and string-type
resource items.  In this non-normative example, the client instance
is requesting access to a "photo-api" and "financial-transaction" API
type as well as the reference values of "read", "dolphin-metadata",
and "some other thing".
Paragraph (version A):
The AS responds with a token as described in response.
Paragraph (version A):
If the RS needs to, it can post a set of resources as described in
request-resource-single to the AS's resource registration endpoint.
Paragraph (version B):
The AS responds with a token for the downstream RS2 as described in
response-token.
Paragraph (version B):
If the RS needs to, it can post a set of resources as described in
resource-access-rights to the AS's resource registration endpoint.
Paragraph (version A):
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 request-
resource.  This resource reference handle SHOULD be sufficient for at
least the action the client instance was attempting to take at the
RS.  The RS MAY use the rs-register-resource-handle to register a new
resource handle, or use a handle that has been pre-configured to
represent what the AS is protecting.  The content of this handle is
opaque to the RS and the client instance.
Paragraph (version B):
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 request-
token.  This resource reference handle SHOULD be sufficient for at
least the action the client instance was attempting to take at the
RS.  The RS MAY use the rs-register-resource-handle to register a new
resource handle, or use a handle that has been pre-configured to
represent what the AS is protecting.  The content of this handle is
opaque to the RS and the client instance.
Paragraph (version A):
The client instance then makes a call to the "as_uri" as described in
request, with the value of "resource" as one of the members of a
"resources" array request-resource-single.  The client instance MAY
request additional resources and other information, and MAY request
multiple access tokens.
Paragraph (version B):
The client instance then makes a call to the "as_uri" as described in
request, with the value of "resource" as one of the members of the
"access" array request-token-single.  The client instance MAY request
additional resources and other information, and MAY request multiple
access tokens.