Oauth 2.0 - Resource Owner (user) specific tokens

Not applicable

Here are my Requirements:

Secure APIs through RO Password grant-type, such that the end-user is able to retrieve only her/his own data.

What I have done so far:

  1. Password grant
    1. Setup a token endpoint with password grant
    2. When the request comes in, I first extract the RO credentials using an extract variable policy.
    3. TODOs:
      1. Validate UserId/Password against a user store (planning to use UserGrid)
      2. Return an associated Customer Id from the user-store
    4. If the Userid/Password is valid, I then go to the next step – Oauth 2 policy to generate token
    5. TODO:
      1. Have to add Customer Id retrieved to the response before returning it to the caller.
  2. API endpoint
    1. Secured the API with Oauth 2 policy to validate token
    2. TODO:
      1. Tie validation of the token with the Customer Id. Meaning, the token should be tied to the customer credentials/Id that was used to generate the token. I should not be able to call the API on behalf of Cust B if the token I am using was generated using the credentials for Cust A.

Questions:

  • How do I achieve step 2.2.1 above? Currently the all the validation step does is validates the token irrespective of the customer Id tied to it.
  • In the flow for Password grant, I am first checking user (RO) credentials and then the client credentials, which to me is counter logic. Can I first check client credentials and then RO credentials?

Note: I am not talking about Developer Id here. My customers are not registered in Edge. They are registered in my Customer IdAM (in this POC, the UserGrid).

Thanks in advance.

Solved Solved
0 6 943
1 ACCEPTED SOLUTION

Not applicable

I will try to answer the second question first...

Before even hitting your IdAM, it is good idea to check if the call is coming from valid app. Hence, client credentials validation should be first anyway.

Now coming to the first one,

I will implement it as below

1. perform the client credentials authentication

2. perform RO authentication which will return customerid

3. while generating the access token (password grant), associate additional custom attribute -- customerid

4. return access token to the consumer.

5. Now, in the API endpoint, verify the access token and retrieve the custom attribute -- customerid and use it for the backend requests.

This way, Cust A and Cust B will always "only" get their own data from backend.

Some samples:

Generate Access Token

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="GenerateAccessToken">
    <DisplayName>GenerateAccessToken</DisplayName>
    <Operation>GenerateAccessToken</Operation>
    <ExpiresIn>360000000</ExpiresIn>
    <SupportedGrantTypes>
        <GrantType>password</GrantType>
    </SupportedGrantTypes>
    <!-- Attaching end customerid to accesstoken after validation -->
    <Attributes>
        <Attribute name="customerid" ref="flow.var.customerid"/>
    </Attributes>
    <Scope>request.formparam.scope</Scope>
    <GenerateResponse enabled="false"/>
</OAuthV2>

After successful verify access token, the custom attribute will be available using flow variable

accesstoken.customerid

View solution in original post

6 REPLIES 6

Not applicable

I will try to answer the second question first...

Before even hitting your IdAM, it is good idea to check if the call is coming from valid app. Hence, client credentials validation should be first anyway.

Now coming to the first one,

I will implement it as below

1. perform the client credentials authentication

2. perform RO authentication which will return customerid

3. while generating the access token (password grant), associate additional custom attribute -- customerid

4. return access token to the consumer.

5. Now, in the API endpoint, verify the access token and retrieve the custom attribute -- customerid and use it for the backend requests.

This way, Cust A and Cust B will always "only" get their own data from backend.

Some samples:

Generate Access Token

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="GenerateAccessToken">
    <DisplayName>GenerateAccessToken</DisplayName>
    <Operation>GenerateAccessToken</Operation>
    <ExpiresIn>360000000</ExpiresIn>
    <SupportedGrantTypes>
        <GrantType>password</GrantType>
    </SupportedGrantTypes>
    <!-- Attaching end customerid to accesstoken after validation -->
    <Attributes>
        <Attribute name="customerid" ref="flow.var.customerid"/>
    </Attributes>
    <Scope>request.formparam.scope</Scope>
    <GenerateResponse enabled="false"/>
</OAuthV2>

After successful verify access token, the custom attribute will be available using flow variable

accesstoken.customerid

Thanks for your help. it is working now. 🙂

Hi @Ritwik Chatterjee - You can embed the Customer ID as a custom attribute in your token. You can do this while generating the token.

For eg - The customerID could be extracted from the Usergrid response (step 3.2).

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuth-v20-1">
    <Operation>GenerateAccessToken</Operation>
    <ExpiresIn>360000000</ExpiresIn>
    <SupportedGrantTypes>
        <GrantType>password</GrantType>
    </SupportedGrantTypes>
    <Attributes>
        <Attribute name="CustomerID" ref="customerID"/>
    </Attributes>
    <GrantType>request.queryparam.grant_type</GrantType>
    <UserName>request.queryparam.username</UserName>
    <PassWord>request.queryparam.password</PassWord>
    <GenerateResponse/>
</OAuthV2>

In your token verification flow, the VerifyAccessToken policy populates this variable if the token is valid. You can then match the Customer Id in your incoming request with what's there in the token.

Question 2 - I guess you are referring to validating "client credentials" in Apigee. You could put a VerifyAPI key to at least verify the client as a first step. The "GenerateAccessToken" policy automatically check for Client ID and secret before generating the token.

Thanks!

Thanks for your help

@Ritwik Chatterjee

Ravi shah has correctly provided the solution.

I also wanted to know if you also require to create REFRESH TOKEN Flow.

This will ensure that once your access token is expired, you can get access token via Refresh token.

I hope you are also aware about the fact that according to the OAUTH Specification, in REFRESH TOKEN flow , you do not need to verify the Consumer username and password (in your case RO Credentials)

Please let me know in case you need to create REFRESH TOKEN FLOW.

Also, few more things.

1) Verify ACCESS Key just verifies the Client ID and it does not check if the client secret is correct or not.

2) So when you add the Verify access key at the beginning of the flow, you are only validating the Client Key

3) So you need to add few more policies to verify the Client secret.

Please let me know if you need the logic for verifying the client secret.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><OAuthV2async="false"continueOnError="false"enabled="true"name="GenerateAccessToken"><DisplayName>GenerateAccessToken</DisplayName><Operation>GenerateAccessToken</Operation><ExpiresIn>360000000</ExpiresIn><SupportedGrantTypes><GrantType>password</GrantType></SupportedGrantTypes><!-- Attaching end customerid to accesstoken after validation --><Attributes><Attributename="customerid"ref="flow.var.customerid"/></Attributes><Scope>request.formparam.scope</Scope><GenerateResponseenabled="false"/></OAuthV2>