Client Credentials Grant with ability to pass User Claims

I have the need to provide some information to a third party product.

The third party product manages the user base on it's systems and assigns it's users a Role.

When a request comes in for getting a token - I need to bind this Role to the token.

I would then later use this Role to verify if the user can get access to some resource in my back end api.

From my current understanding it seems to be a Client Credentials Grant (authorise the client app). But how do I capture the Role?

Or should I be using a different oAuth 2 Flow?

- It would be ideal if the request for token can pass the Role to me somehow as part of the oAuth 2 Process.

0 2 3,705
2 REPLIES 2

I think ....

  1. "client credentials" grant is intended to provide a token for a CLIENT only. It authenticates the CLIENT, which is the app in question. There is no thought of a user, when employing the client credentials grant type. CC should be used when it's one service talking to another service.
  2. If you want to authenticate the user as well as the client (app) then you need to look into Authorization Code flow, or Password grant flow. Which one you use depends on the client, and whether it is trusted or not. Password grant flow calls for the client itself to handle user credentials and pass them to the oauth token server. This means the client must be trusted. You cannot allow this if you are serving 3rd party clients. Asking your users to key in their credentials into 3rd party clients is a Bad Idea, for obvious reasons. A malicious client could collect and store user credentials and then re-use them without user approval. Obviously wrong. But a password grant works well when you trust the client in question - for example the client app is built by YOU, or someone in your company that you trust.
    Authorization Code grant type is useful for 3rd party clients. It uses HTTP redirection to allow the user to authenticate via the trusted user agent (the browser) and then sends back a code for the app to exchange for a token. The app (client) itself handles the code, but never handles user credentials.

Here's a hands-on lab exercise that shows you how to do Password Grant with Apigee Edge. And here is the Proxy that dispenses tokens via PG.

OK, now, beyond the grant type...

The real question you asked was "how can I attach the user role to the token?" And the answer is "custom attributes". There are two moments

  1. At the time of token generation.
    When you use the OAuthV2/GenerateAccessToken policy, specify a custom attribute to hold the role. It might look like this:

     <Attributes>
        <Attribute name='authenticated_user'
                   ref='userauth.user.email'
                   display='true'>UNDEFINED</Attribute>
        <Attribute name='grant_type'
                   ref='request.formparam.grant_type'
                   display='true'>UNDEFINED</Attribute>
        <Attribute name='user_groups'
                   ref='userauth.user.groups'
                   display='true'>[]</Attribute>
      </Attributes>
    	

    Look in the sample token dispensing proxy that I referenced above for the full example policy configuration. It uses "user groups" but the idea is the same. This group or role information is sent back by the IdP that your token dispenser uses to authenticate the user.

  2. At the time of token verification.
    When you use OAuthV2/VerifyAccessToken, the custom attributes attached to the original token are implicitly brought into the context via variables. You can then include Conditions in your proxy flow to examine the variables, and then determine what you want to do with those variables. OR, you could call out to an external authorization service (not provided by Apigee) to inquire "should I allow this operation?" . Basically you send out a tuple of {role, resource, action} , for example {reader, /foo/bar, GET} and the authorization services returns a yes or a no. The lab exercise proxy shows how to do that.

I have struggled with this use case myself so i thought i'd put my thoughts here and see if they stand the community challenge.

I have no doubt in my mind that Authorization Code Grant should be the preferred way to go for third party integrations. But i don't think it is always practical/feasible in the scenario you listed.

Imagine a scenario where a trusted partner hosts a website and uses API's from multiple providers to create their home page experience. Each of them followed the Authorization Code Grant approach, this would basically mean that the end user would have to login multiple times (for each provider) before they land on the home page. That would lead to a very crappy user experience.

So, i think when

  • A trusted legal relationship exists between two business entities
  • The API provider(s) do not manage/store the user identity

Client Credentials would be the preferred approach.Yes, the grant type was created for Service-Service accounts but this is exactly that scenario because your API does not know the end user and cannot validate the end user. As far as your API is concerned, a real live user does not exist. Only a role does.So, the client could use a service account to fetch data from your API and somehow propagate the end user's role context.

The client(Third Party Product) would create a JWT to embed user claims. This token could then be propagated to API Providers who can verify the token and extract the claims

Dino's suggestion on attaching the Role during the Access Token Generation process(extracted from the JWT claim) would be perfectly valid if the Third Party product requests an access token per user. I am not sure if it should. Your system doesn't know the user, it only knows the user role. You could perhaps create an access token per role but then you are forcing the client to keep track of role-access token mappings. It's easier to track the access token for the user.

Personally, i would prefer that the JWT token is embedded in the Data Request Call (not in the Generate Token Call), a shared flow would extract the role and perform the entitlement checks required for data access.

fyi, there is a proposed standard for JWT Bearer Authorization Grant Type

https://tools.ietf.org/html/rfc7523