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! Go to Solution.
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-
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.