Impact of grant_management_action=update on AT implementation and introspection

Issue #455 resolved
Takahiko Kawasaki created an issue

Impact of grant_management_action=update on access token implementation and introspection will be bigger than the impression the specification may give if the specification expects (and probably does) that the access token generated as a result of grant_management_action=update internally keeps (in other words, does not reduce) relations between scope and resource. At least, the standard specification of access token introspection (RFC 7662) cannot express the relations, so resource server implementations which rely on the standard introspection won’t be able to validate the access token as the grant management specification expects.

Suppose three access tokens are created as below.

  1. grant_management_action=create & scope=s1 & resource=r1grant_id=g1 & access_token=a1
  2. grant_management_action=update & scope=s2 & resource=r2 & grant_id=g1access_token=a2
  3. grant_management_action=update & scope=s3 & resource=r3 & grant_id=g1access_token=a3

After the three authorization requests above, the grant identified by g1 will hold the following information.

{
  "scopes": [
    { "scope":"s1", "resource":["r1"] },
    { "scope":"s2", "resource":["r2"] },
    { "scope":"s3", "resource":["r3"] }
  ]
}

If it were allowed to reduce the relations the access token a3 should maintain to the following,

{
  "scope": "s1 s2 s3",
  "resource": [
    "r1", "r2", "r3"
  ]
}

impact on access token implementation and introspection would be negligible.

On the other hand, if the grant management specification requires that the access token a3 keep the relations in the same way as the grant g1 holds, a new specification needs to be developed as to how to express the relations in access token introspection so that resource servers can protect their APIs based on the information.

For example, an introspection result for the access token a3 should hold information like below where "grant" is the snapshot of the content of the grant g1 when the access token a3 was generated.

{
  "scope": "s3",
  "resource": "r3",
  "grant": [
    { "scope":"s1", "resource":["r1"] },
    { "scope":"s2", "resource":["r2"] }
  ],
  ......
}

Decisions that need to be made are as follows.

  1. Whether to allow information reduction or not
  2. If reduction is not allowed, how to express the snapshot of the grant in access token introspection

Comments (33)

  1. Takahiko Kawasaki reporter

    Sorry, the first "resource" in the example of introspection response should have been "aud" to conform to RFC 8707 Resource Indicators for OAuth 2.0. So, a better example is as follows.

    {
      "scope": "s3",
      "aud": ["r3"],
      "grant": [
        { "scope":"s1", "resource":["r1"] },
        { "scope":"s2", "resource":["r2"] }
      ],
      ......
    }
    

  2. Nicholas Irving

    This sounds similair to a problem I have been experiencing in regards to multi entity relationships. One easily solved if you have a graph database, but if you dont then it is much harder. Say i am an employee for an organisation that manages other organisations and those organisations have many different accounts that the employee can use. For User1 works for OrgA, which manages OrgB/OrgC. OrgB has Acc1, OrgC has Acc2 and User1 can perform OperationA and OperationC for Acc1 because they are granted RoleA and OperationB for Acc2 because of RoleB.
    How can that be represented in a way that a resource server can protect?

    Role: OrgA:RoleA
    Role: OrgB:RoleA
    Role: OrgC:RoleB
    Account: Acc1
    Account: Acc2
    PrimaryOrg: OrgA
    Org: OrgB
    Org: OrgC
    

    This of course is for ABAC, but could be translated.

    This way I can define a policy

    Role: OrgB:RoleA
    Account: Acc1
    
    or
    
    Account: Acc1
    PrimaryOrg: OrgB
    

    This way you dont have to worry about all the complex relationships between Org, Account and Role, have that abstracted through some other means and distilled down into the basic form above.

    {
      "scope": "s3",
      "aud": ["r3"],
      "grant": {
        "role": ["OrgA:RoleA", "OrgB:RoleA", "OrgC:RoleB"],
        "account": ["Acc1","Acc2"],
        "org": ["OrgB", "OrgC"],
        "primaryOrg": "OrgA"
      },
      ......
    }
    

    This way there is no information leakage on what can be done. It is vague enough to abstract it, but powerful enough to provide the coverage needed for a policy decision.

    In essence I agree with what you are proposing and I could use the resource space to manage the complexity of the relationships to bring it more inline with the standard.

    {
      "scope": "s3",
      "resource": "r3",
      "grant": [
        { "scope":"RoleA", "resource":["OrgA", "OrgB/Acc1"] },
        { "scope":"RoleB", "resource":["OrgC/Acc2"] },
      ],
      ......
    }
    

    Thanks for the time to revisit this.

  3. Torsten Lodderstedt

    I think RFC 8707 already requires clustering of resource indicators and scope values passed in the same authorization request, especially if the AS supports the update of a grant in subsequent authorization requests (with a different set of resource indicators and scope values). Grant management just makes this obvious.

    So I support a clarification of that topic and definition of new claim/response parameter to facilitate this logic.

  4. Brian Campbell

    RFC8707 is silent on what it means for an AS to combine the data of multiple authorization requests into a single "grant". Honestly, when writing it, I'd just assumed that each such authorization request would be treated as a different grant so didn't even think to give the subject any consideration in the document. As Taka has pointed out, however, the concepts in Grant Management change that assumption and introduce a bit of a mismatch in how the authorization grant data is conveyed and stored. I don't think that introducing a new structure to access tokens (JWT / introspection) is the appropriate solution here though. It would push complexity and changes into access tokens and RSs for a situation that's likely to be uncommon even if allowed by Grant Management. I'd rather see the Grant Management API structure flattened out and just allow for scope and resource to accumulate over many grant updates. Or some notes or advice or rules be added about handling RT requests against such a grant - like mention the potential loss of fidelity in the authorization grant data of a resultant access token and/or require/suggest that ASs reject such requests and have clients dealing with this kind of grant narrow the resources/scope of requested access tokens with the resource parameter.

  5. Takahiko Kawasaki reporter

    Flattening will make AS implementations simpler. Its downside is that the specification has to give up supporting some use cases.

    A flexible approach is to leave the interpretation to AS implementations. Its downside is that it harms interoperability.

    A new server metadata denoting the type of interpretation may be able to mitigate the interoperability problem. The type "flattening" won't have any impact on structures of introspection response and JWT access tokens (and RS implementations) at the sacrifice of fidelity and some use cases. The other type will need to update the structures (and RS implementations) for fidelity and wider range of use cases. The common point between both types is that grant IDs are issued and can be managed. Respective ecosystems may allow both types or may choose either depending on their policies.

  6. Torsten Lodderstedt

    @Filip Skokan Would flattening scopes & resources as suggested by Brian work for your implementation?

  7. Filip Skokan
    1. the grant representation from section 6.4. in ID1 works fine, I cannot imagine why we’d need to flatten anything there.
    2. multiple scope/resource representation inside JWT Access Tokens or Introspection is not a new problem introduced by Grant Management. It is a problem that an AS supporting issuing ATs for multiple audiences brings upon itself.

    Don’t issue access tokens for multiple audiences. I wouldn’t want to end up in a scenario where a commonly used scope value would appear as granted to a resource which did not have that scope explicitly listed in its transaction details.

    Can we not require that ATs issued in FAPI2 to only have a single audience? This does not preclude authorization requests containing multiple resources and scopes for those, but the resulting AT must only contain one of them, the resource parameter during auth code exchange can be used to decide which one is issued first, and a RT is used to get an AT for the other resource, repeat for any additional resource.

  8. Takahiko Kawasaki reporter

    I don’t figure out what the restriction of “one resource per access token” is trying to solve. The example I showed is already “one resource per access token” for simplicity.

  9. Filip Skokan

    And yet.

    a3 should not have s1, s2, r1, or r2 in the first place. so in your example the grant does have s1>r1, s2>r2, s3>r3, but the individual access tokens don’t.

    If a single resource pet AT principle is used, in order for the resulting Refresh Token from the third authorization request to have the ability to get s1 it would have to include r1 and s1 in the first update authorization request. Then that RT could be used by the Client to get tokens for either r1 or r3, but never both.

    If a single resource pet AT principle is used, in order for the resulting Refresh Token from the third authorization request to have the ability to get s2 it would have to include r2 and s2 in the second update authorization request. Then that RT could be used by the Client to get tokens for either r2 or r3, but never both.

    Accumulating scopes and resources in a grant does not imply implicitly adding them to access tokens issued based on that grant.

  10. Takahiko Kawasaki reporter

    Hoping I’m not misunderstood, my personal opinion is that the following (flattening) should NOT happen (so I think I’m in the same position with you in this point).

    {
      "scope": "s1 s2 s3",
      "resource": [
        "r1", "r2", "r3"
      ]
    }
    

  11. Filip Skokan

    Great.

    then in order to answer the two proposed questions that need answers

    Whether to allow information reduction or not

    No. And is it implied to be reducible like so? I hope not and would like to know what triggered that chain of thought in the first place.

    {
      "scope": "s1 s2 s3",
      "resource": [
        "r1", "r2", "r3"
      ]
    }
    

    If reduction is not allowed, how to express the snapshot of the grant in access token introspection

    I don’t think we have to come up with one. It’s not a new problem introduced by GM. If anything we could try and prevent it altogether by enforcing a single resource per AT in FAPI2.

  12. Takahiko Kawasaki reporter

    A possible compromise between “should not sacrifice expressiveness” and “should not impact existing deployments” would be to introduce a new server metadata, for example, grant_management_accumulation_policy, which can be separate or flatten.

    grant_management_accumulation_policy=separate

    introspection response & JWT access token

    {
      "scope":"s3",
      "aud":["r3"],
      "grant": {
        "scopes": [
          {"scope":"s1","resource":["r1"]},
          {"scope":"s2","resource":["r2"]}
        ]
      }
    }
    

    grant management response for query

    {
      "scopes": [
        {"scope":"s1","resource":["r1"]},
        {"scope":"s2","resource":["r2"]},
        {"scope":"s3","resource":["r3"]}
      ]
    }
    

    grant_management_accumulation_policy=flatten

    introspection response & JWT access token

    {
      "scope":"s1 s2 s3",
      "aud":["r1","r2","r3"]
    }
    

    grant management response for query

    {
      "scopes": [
        {"scope":"s1 s2 s3","resource":["r1","r2","r3"]}
      ]
    }
    


    Existing resource servers can continue to function without modification when grant_management_accumulation_policy is flatten. On the other hand, GM-aware resource servers can provide richer access control when grant_management_accumulation_policy is separate.

    One more flexibility would be to add a new request parameter (grant_management_accumulation_policy or something else that provides the same functionality) to the standard introspection endpoint so that resource servers can request the authorization server to adjust the format of the introspection response at runtime. (but it may be too early to discuss this now…)

  13. Filip Skokan

    I don’t believe either is a good idea.


    Flattening makes it seem like the resource server receiving an AT was granted more than it actually was and I wish we just didn’t recognise that as a possibility at all, or that we outright forbid it by ensuring a single audience.

    At the same time, enriching introspection or structured access tokens with information unrelated to the AT’s actual resource indicator is unseemly.

  14. Takahiko Kawasaki reporter

    Flattening makes it seem like the resource server receiving an AT was granted more than it actually was

    I understand the problem, but this is what Brian suggested.

    BTW, if you think that the number of resources tied to an access token should be at most one, what should happen when an authorization request is made with grant_management_action=update and with a resource which is different from the resource tied to the grant?

    For example, what should happen when the authorization requests below are made?

    1. grant_management_action=create & scope=s1 & resource=r1grant_id=g1 & access_token=a1
    2. grant_management_action=update & scope=s2 & resource=r2 & grant_id=g1access_token=a2

    Do you mean that the second authorization request should be rejected because its resource is different from the resource of the first request?

  15. Filip Skokan

    I’m not equalling the state of the grant with what’s shoved in an issued access token. So, the request goes through, a2 has s2 and r2.

    And in order for the client to be able to communicate with r1 using artefacts issued from the second request it

    1. includes s1 and r1 in the authorization request (since automatically adding previously granted scopes and resources to authorization requests is not the behaviour defined by GM, it could be, in which case it is only a convenience for the client not have to be explicit about each authorization request, which i don’t really like)
    2. requests a refresh token
    3. Uses the resource parameter at the code exchange and/or rt exchange grants to indicate which of the granted resources it wants an AT for. Each AT has a single resource. But it’s the RT that holds the keys to be able to communicate with different resources.

  16. Takahiko Kawasaki reporter

    I’m not equalling the state of the grant with what’s shoved in an issued access token. So, the request goes through, a2 has s2 and r2.

    And in order for the client to be able to communicate with r1 using artefacts issued from the second request it

    1. includes s1 and r1 in the authorization request (since automatically adding previously granted scopes and resources to authorization requests is not the behaviour defined by GM, it could be, in which case it is only a convenience for the client not have to be explicit about each authorization request, which i don’t really like)

    Well, if the second authorization request has to include s1 and r1 in addition to s2 and r2, it contradicts the purpose and definition of the update action.

    From 5.2. Authorization Request:

    • update: this mode requires the client to specify a grant id using the grant_id parameter. If the parameter is present and the AS supports the grant management action update, the AS will merge the permissions consented by the user in the actual request with those which already exist within the grant.

  17. Filip Skokan

    It could be spelled out better I think, because the draft talks about managing the grant that the AS tracks, it is not explicitly changing the semantics of what the authorization request should yield in the issued artefacts.

  18. Takahiko Kawasaki reporter

    It seems to me that the current description of the update action (“the AS will merge the permissions consented by the user in the actual request with those which already exist within the grant”) explicitly changes the semantics. My interpretation is that scopes and resources which are not included in an authorization request may be granted to an access token when grant_management_action is update. Is your interpretation different from mine or are you suggesting changing the behavior of the update action?

  19. Filip Skokan

    I’m not sure if both, or neither. I would definitely welcome suggestion or thoughts from @Brian Campbell on this discussion. Do need to explicitly call out what the client should be doing wrt. code and RT exchange when it comes to the resource parameter when multiple resources have been resolved using this update action way.

    Can we agree that multi resource ATs need to be discouraged/prohibited/put out of scope/be at the AS discretion?

  20. Takahiko Kawasaki reporter

    To be honest, I still don’t figure out demerits of multiple resources per access token. The attached image illustrates a single-resource access token (Access Token 1) and a multi-resource access token (Access Token 2). I don’t figure out why Access Token 2 should be discouraged.

  21. Filip Skokan

    Imagine its rs1.example1.com and rs2.example2.com (as in actually two different entities' resource servers) and a common colliding scope values between resource servers like “api:write” and “api:read”. I can first request rs1 w/ read and write. Then update to add rs2 w/ just read. If a new AT is issued with both audiences and a joined scope value, you’ve got a problem because rs2 now thinks its write has been granted.

  22. Takahiko Kawasaki reporter

    The problem you described will happen if

    (1) An authorization request with scope=read write & resource=https://rs1.example1.com & grant_management_action=create is made, and grant_id=g1 & access_token=a1 are generated.

    (2) Another authorization request with scope=read & resource=https://rs2.example2.com & grant_management_action=update & grant_id=g1 is made, and access_token=a2 is generated.

    (3) The authorization server adopts the “flatten” policy and grants the following privileges to a2.

    {
      "scope": "read write",
      "aud": [
        "https://rs1.example1.com",
        "https://rs2.example2.com"
      ]
    }
    

    However, if

    (3)-(separate) The authorization server adopts the “separate” policy and grants the following privileges to a2,

    {
      "scope": "read",
      "aud": "https://rs2.example2.com",
      "grant": {
        "scopes": [
          {
            "scope": "read write",
            "resource": [
              "https://rs1.example1.com"
            ]
          }
        ]
      }
    }
    

    the problem you worry about will not happen.

    The point is not “single-resource vs multi-resource” but “flatten vs separate”.

    A example of “multi-resource” are as follows.

    (1)-(multi-resource) An authorization request with scope=read write & resource=https://rs1.example1.com/a & resource=https://rs1.example1.com/b & grant_management_action=create is made, and grant_id=g1 & access_token=a1 are generated.

    (2)-(multi-resource) Another authorization request with scope=read & resource=https://rs2.example2.com/c resource=https://rs2.example2.com/d & grant_management_action=update & grant_id=g1 is made, and access_token=a2 is generated.

    (3)-(multi-resource)-(flatten) The authorization server that adopts the “flatten” policy grants the following privileges to a2.

    {
      "scope": "read write",
      "aud": [
        "https://rs1.example1.com/a",
        "https://rs1.example1.com/b",
        "https://rs2.example2.com/c",
        "https://rs2.example2.com/d"
      ]
    }
    

    On the other hand,

    (3)-(multi-resource)-(separate) The authorization server that adopts the “separate” policy grants the following privileges to a2.

    {
      "scope": "read",
      "aud": [
        "https://rs2.example2.com/c",
        "https://rs2.example2.com/d"
      ],
      "grant": {
        "scopes": [
          {
            "scope": "read write",
            "resource": [
              "https://rs1.example1.com/a",
              "https://rs1.example1.com/b"
            ]
          }
        ]
      }
    }
    

    Under the “separate” policy, the problem you worry about won’t happen even if multiple resources are tied to an access token.

  23. Filip Skokan

    The point is not “single-resource vs multi-resource” but “flatten vs separate”.

    I disagree. Flatten vs separate only comes up as a result of having multiple resources in an AT in the first place. This is a bad practice that, for reasons eluding me, keeps on crawling back despite trying to forbid it early on in Resource Indicators as well as the recent JWT AT work.

    This is diving into the territory of “complex authorization detail structures” for which we have the RAR specification conditionally required in FAPI2. We can therefore consider forbidding multi audience access tokens in FAPI2 and save ourselves the pain of coming up with a new structure to represent access tokens (JWT / introspection). It is imho not appropriate for GM to do so.

  24. Takahiko Kawasaki reporter

    I now understand. The problem we want to solve is the same, but solutions for the problem are different. Your solution is “Prohibit tying multiple resources to an access token” (and the behavior of the update action needs to be changed accordingly). My solution is "Extend the formats of introspection response and JWT access token". This is a matter of preference.

    My preference is “Extend the formats” because the restriction of “at most single resource per access token” is too strict and deprives developers/ecosystems of flexibility in API design and access control design.

  25. Takahiko Kawasaki reporter

    A possible approach to allow both preferences to coexist is to add text like below.

    Authorization server implementations may restrict the number of resources tied to an access token to at most one. Behaviors of such implementations when an authorization request includes the resource request parameter multiple times are at the discretion of the implementations. For example, the authorization request may be rejected or may succeed with issuance of an access token tied to one of the specified resources. The logic of resource selection also is up to implementations.

    Likewise, behaviors of authorization server implementations with single resource policy when the resource tied to the grant specified by the grant_id request parameter is different from the resource specified by the resource request parameter are at the discretion of the implementations. For example, the authorization request may be rejected or may succeed by overwriting or not overwriting the resource tied to the grant.

  26. Brian Campbell

    Sorry if the suggestion to flatten the grant structure confused the conversation. I just want to avoid seeing a big fix to this arguable edge situation ripple through into ugly things that impact other established parts of OAuth.

  27. Torsten Lodderstedt

    The problem as I see it is that complex structures resulting from multiple authz transactions cannot be conveyed via “aud” and “scope” claims values in JWTs or Introspection Response (as suggested by RFC 8707, section 2). However, I think it is anyway recommended practice to mint audience restricted access tokens. So I would suggested to add implementation advise to issue audience restricted access tokens/create audience restricted introspection responses utilizing aud & scope.

    Access Tokens & Introspection Responses

    The grant resource's data model serves the purpose of making the content of a grant transparent to the respective client. The way grant data (e.g. scopes) is conveyed between AS and RS is at the discretion of AS and RS.

    Deployments should ensure access tokens are issued with an audience restricted to a certain resource server. This is good security practice and it allows implementations implementations to use the existing claim aud to convey the resource value in addition to the scope claim in access tokens and respective introspection responses.

  28. Log in to comment