Encapsulate external OAuth

juanarias
Participant I

Hi all,

I want to encapsulate OAuth 2.0 authentication inside apigee. That means, the client will send only an API key (taken from developer app) and, inside the flow, I want to make the OAuth authentication.

This is my current working configuration:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Verify-API-Key</Name>
            </Step>
            <Step>
                <Name>OAuth-Service-Callout</Name>
            </Step>
            <Step>
                <Name>Extract-OAuth-Token</Name>
            </Step>
            <Step>
                <Name>Assign-OAuth-Token</Name>
            </Step>
            <Step>
                <Name>SaveAccessToken-OAuth-v20</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

The OAuth-Service-Callout invokes the external OAuth server and gets the token. That works fine.

The Extract-OAuth-Token takes the token from the response and assign it to a local variable called external_token. Pretty simple.

The Assign-OAuth-Token looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Assign-OAuth-Token">
    <DisplayName>Assign OAuth Token</DisplayName>
    <Set>
        <Headers>
            <Header name="Authorization">Bearer {external_token}</Header>
        </Headers>
        <FormParams>
            <FormParam name="client_id">{apigee.client_id}</FormParam>
            <FormParam name="grant_type">client_credentials</FormParam>
        </FormParams>
    </Set>
    <AssignVariable>
        <Name>oauth_external_authorization_status</Name>
        <Value>true</Value>
    </AssignVariable>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

And the SaveAccessToken-OAuth-v20 looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="SaveAccessToken-OAuth-v20">
    <DisplayName>SaveAccessToken OAuth v2.0</DisplayName>
    <Operation>GenerateAccessToken</Operation>
    <ExternalAuthorization>true</ExternalAuthorization>
    <ExternalAccessToken>external_token</ExternalAccessToken>
    <StoreToken>true</StoreToken>
    <GenerateResponse enabled="false"/>
    <Tokens/>
</OAuthV2>

This is working, and if I call the proxy with the propper API key, I get a success response, with data from target endpoint. In the trace I can see the call to OAuth server, the generated token and so on.

That works fine, but it needs some optimizations.

I would like to only perform the service callout the first time. After I get the token, I want to store it in Apigee to be used in the following calls. At least, while the token is valid.

And only call again the OAuth server, the server callout, once the token is expired.

I'm trying to add a this at the beginning of the flow, but it's NOT working. It throws a 401 HTTP error, but I can't see any messages or descriptions about what failed.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="ValidateTokenOAuth-v20">
    <DisplayName>ValidateTokenOAuth v2.0</DisplayName>
    <Operation>VerifyAccessToken</Operation>
    <ExternalAuthorization>true</ExternalAuthorization>
    <GenerateResponse enabled="true"/>
    <Tokens/>
</OAuthV2>

What do you think about the approach? What am I missing?

Thanks in advance!

Juan

Solved Solved
0 6 479
1 ACCEPTED SOLUTION

sidd-harth
Participant V
I would like to only perform the service callout the first time. After I get the token, I want to store it in Apigee to be used in the following calls. At least, while the token is valid.
And only call again the OAuth server, the server callout, once the token is expired.

Hi @Juan Gabriel Arias, we can make use of Cache Policies to achieve this.

We should be using LookupCache(LC) before ServiceCallout(SC) & PopulateCache(PC) after Extract-OAuth-Token Policy(EV) with few Conditions.

First Call

When a first call is made, the LC will be empty and we will use this as a condition to SC Policy.

The SC policy will execute and give a token with the expiry time.

We will store this token and expire time in PC to create a cache.

Second Call

When the second call comes, the LC will find the token in the cache and will skip the SC, EV and PC policy until the token expiry time.

I might have implemented this earlier, I will edit this answer if I found the proxy.

-edit-

7617-policies.jpg

First, execute Service Callout Policy and use Extract Variable policy to get the Token & Expire time.

Let's say the extracted variables are extracted_token & extracted_expire_time

Then use a Populate Cache,

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PopulateCache async="false" continueOnError="false" enabled="true" name="Populate-Cache-1">
    <DisplayName>Populate Cache-1</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix>oauthToken</Prefix>
        <KeyFragment>1</KeyFragment>
    </CacheKey>
    <Scope>Exclusive</Scope>
    <ExpirySettings>
        <TimeoutInSec ref="extracted_expire_time"/>
    </ExpirySettings>
    <Source>extracted_token</Source>
</PopulateCache>

LookUpCache

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LookupCache async="false" continueOnError="false" enabled="true" name="Lookup-Cache-1">
    <DisplayName>Lookup Cache-1</DisplayName>
    <Properties/>
    <AssignTo>cached.oauth</AssignTo>
    <Scope>Exclusive</Scope>
    <CacheKey>
        <Prefix>oauthToken</Prefix>
        <KeyFragment>1</KeyFragment>
    </CacheKey>
</LookupCache>

Steps

	    <Step>
                <Name>Lookup-Cache-1</Name>
            </Step>
            <Step>
                <Name>Service-Callout-1</Name>
                <Condition>cached.oauth = null</Condition>
            </Step>
            <Step>
                <Name>Populate-Cache-1</Name>
                <Condition>cached.oauth = null</Condition>
            </Step>

This is a basic example, you may need to add a few more Conditions for better control and error handling.

View solution in original post

6 REPLIES 6

sidd-harth
Participant V
I would like to only perform the service callout the first time. After I get the token, I want to store it in Apigee to be used in the following calls. At least, while the token is valid.
And only call again the OAuth server, the server callout, once the token is expired.

Hi @Juan Gabriel Arias, we can make use of Cache Policies to achieve this.

We should be using LookupCache(LC) before ServiceCallout(SC) & PopulateCache(PC) after Extract-OAuth-Token Policy(EV) with few Conditions.

First Call

When a first call is made, the LC will be empty and we will use this as a condition to SC Policy.

The SC policy will execute and give a token with the expiry time.

We will store this token and expire time in PC to create a cache.

Second Call

When the second call comes, the LC will find the token in the cache and will skip the SC, EV and PC policy until the token expiry time.

I might have implemented this earlier, I will edit this answer if I found the proxy.

-edit-

7617-policies.jpg

First, execute Service Callout Policy and use Extract Variable policy to get the Token & Expire time.

Let's say the extracted variables are extracted_token & extracted_expire_time

Then use a Populate Cache,

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PopulateCache async="false" continueOnError="false" enabled="true" name="Populate-Cache-1">
    <DisplayName>Populate Cache-1</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix>oauthToken</Prefix>
        <KeyFragment>1</KeyFragment>
    </CacheKey>
    <Scope>Exclusive</Scope>
    <ExpirySettings>
        <TimeoutInSec ref="extracted_expire_time"/>
    </ExpirySettings>
    <Source>extracted_token</Source>
</PopulateCache>

LookUpCache

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LookupCache async="false" continueOnError="false" enabled="true" name="Lookup-Cache-1">
    <DisplayName>Lookup Cache-1</DisplayName>
    <Properties/>
    <AssignTo>cached.oauth</AssignTo>
    <Scope>Exclusive</Scope>
    <CacheKey>
        <Prefix>oauthToken</Prefix>
        <KeyFragment>1</KeyFragment>
    </CacheKey>
</LookupCache>

Steps

	    <Step>
                <Name>Lookup-Cache-1</Name>
            </Step>
            <Step>
                <Name>Service-Callout-1</Name>
                <Condition>cached.oauth = null</Condition>
            </Step>
            <Step>
                <Name>Populate-Cache-1</Name>
                <Condition>cached.oauth = null</Condition>
            </Step>

This is a basic example, you may need to add a few more Conditions for better control and error handling.

Thanks! for the quick answer! Looks that it work, great.

I still have some questions... And what is the purpose of the OAuth policies? Should I remove them?

What does the GenerateAccessToken with StoreToken=true do? Where is stored the token after that policy is executed?

Now that depends on your requirement.

You have 2 Options.

Option 1 -

Directly use the token you are getting from Service Callout & pass it to the TargetService.

In this option since you are using an external token, The drawback is that you'd lose out on developer- and app-specific metrics and targeted traffic control (like quota enforcement), because Apigee needs to know about the developers and apps (by being registered in Edge).

Option 2 -

To overcome above Drawback, Apigee allows storing external tokens. This is where you will be using OAuth policies with StokeToken.

Check this docs for more info,

https://community.apigee.com/questions/44651/can-i-use-external-oauth-and-still-access-develope.html

https://docs.apigee.com/api-platform/security/oauth/use-third-party-oauth-system

@Siddharth Barahalikar

if we use Option 1 but adding a Verify API Key policy at the very beggining, won't that be enough?

Your scenario is to use external oauth. VerifyAPIKey policy is used for verifying Apigee minted API/Consumer Key.

Maybe I don't know the whole requirement.

Please modify/create a question to explain your existing systems and what you want to do in Apigee?

That is the original question, how can I store the external token? Where is stored? What is the purpose of OAuth policies?

You answer works great and I im using it to store the token in the cache. But I'm not using OAuth policies at all.

I've read those links, and the "Using Third-Party OAuth Tokens" doesn't explain how to avoid multiple callings to the OAuth server when you already have the token stored.

And I couldn't make it work anyway, because I cannot store the token or retrieve it from Apigee tokens storage neither.