How to Expose a Third-Party OAuth-Protected API Transparently Through Apigee?

 

 

Hello everyone,

I am currently working on a project where I need to expose a third-party API through Apigee. This third-party API is protected using OAuth. I would like to abstract away the OAuth process, so that the consumer app can call the API without directly dealing with the OAuth authentication steps.

Here's what I am envisioning:
1. Consumer app makes a request to my Apigee endpoint.
2. Apigee handles the OAuth authentication with the third-party API (fetching the token, refreshing it, etc.).


I would appreciate any guidance on how to set this up in Apigee, especially the part where Apigee handles the OAuth steps.

Thank you in advance for your help

0 1 149
1 REPLY 1

In general, you can configure Apigee proxies to "mediate security" so that the security used on the backend/target/upstream is different than the security used on the Apigee inbound endpoint.  By which I mean, maybe the backend requires a JWT bearer token of a particular kind; you can configure Apigee to accept and validate an API key, and then generate the right JWT at runtime, and send that to the backend. Or vice versa. And the general case is true - Apigee can mediate between any two different kinds of credential. opaque tokens to keys, keys to opaque tokens, keys to JWT, keys to HTTPSignature, tokens to HTTPSignature, etc. In my experience, this is one of the most powerful capabilities of Apigee especially for mature enterprises, in which there is a heterogeneous variety of upstream systems - some custom, some off-the-shelf, some SaaS, some legacy, etc - with differing security requirements. That variety is inevitable in a large organization, but you don't want to force client apps to deal with that. So you can use Apigee to put a consistent facade over all of the upstream systems so that all clients can use a consistent approach, and Apigee takes care of the mediation. 

Your requirement is a little curious in that it sounds like you want to strip security off. In other words, you don't want Apigee to validate anything, and then you want Apigee to authenticate to some backend system. That sounds kinda loose, very unusual.  I'd caution against it. Unless of course you're purposefully doing that. I cannot imagine a legitimate reason for doing that.  (Sometimes we get questions on this forum from people who want to use Apigee to do something not quite respectable.  I don't like such questions. They're usually a waste of everyone's time.) 

But to answer your question, sure, you can configure Apigee to act as an OAuth client. IF you know Oauth, you know there are different flows, and some of them are usable only with human interaction.  These are called, in the parlance, "3 legged flows", and the most common is "authorization code flow" which is used by OpenID Connect. (Sometimes with a PCKE validation).  You cannot configure Apigee to engage in a 3-legged flow with full automation, because the 3-legged flow will require a human to login and consent to the scopes. I mean, Apigee can proxy a 3-legged flow (See screencast here, and example configuration here), but to make it all work, at some point the user will have to sign-in and click a box saying "I consent", and only after that can the token be generated. 

The 3-legged flow authenticates both the client (or app) and the user.  But there are other flows in OAuth that authenticate only the client. Sometimes these are grouped into the category of "2-legged flows".  Client_credentials is the most common example.  googleapis supports a grant_type called "urn:ietf:params:oauth:grant-type:jwt-bearer".  And I guess there would be others. In this case, the client presents credentials to a token dispensary, and the token dispensary returns a token.  Simple.  And in that case, of course Apigee can act as the client. 

To make this happen you will need to

  • store credentials in such a way that Apigee can access them.  Like in a KVM, or a properties file. These credentials will vary, depending on what the token dispensary requires. For example, for oauth.googleapis.com, the required request-for-token is a  JWT signed with RS256, therefore the requisite credential is a private RSA key.  For other endpoints, the credentials might be a clientid + clientsecret pair.  Or something else. In any case you need to store that so that the Apigee proxy can access it at runtime.
  • Then use a ServiceCallout to send the HTTP request-for-token to the token dispensing endpoint. This is probably a POST request, and it should carry whatever credentials are required. 
  • Use ExtractVariables to extract the issued token from the response
  • You probably want to wrap that all up in a cache, using LookupCache before the sequence of ServiceCallout + ExtractVariables, and PopulateCache after it.  Tokens are re-usable so you shouldn't want to get a new token for each new request. 
  • Then, in the Target Request flow, use AssignMessage to Set a header, probably the Authorization header , to hold "Bearer {generated_token}" .

In the end your step sequence might look something like this:

  <!--
       Try to load a bearer token for from cache into a context
       variable.  If nothing in cache, Get a new bearer token, and place
       it into a context variable, and also put it in the cache.
  -->

  <Step>
    <Name>LookupCache-Bearer-Token</Name>
  </Step>
  <Step>
    <Name>KVM-Get-AuthenticationCredentials</Name>
    <Condition>cached_bearer_token = null</Condition>
  </Step>
  <Step>
    <Name>JS-ShredCredentialsJson</Name>
    <Condition>cached_bearer_token = null</Condition>
  </Step>
  <Step>
    <Name>SC-Post-to-get-New-Token</Name>
    <Condition>cached_bearer_token = null</Condition>
  </Step>
  <Step>
    <Name>AM-Extract-Issued-Token</Name>
    <Condition>cached_bearer_token = null</Condition>
  </Step>
  <Step>
    <Name>PopulateCache-Issued-Token</Name>
    <Condition>tokenResponse != null</Condition>
  </Step>

The specific configuration for each of those policies will depend on the signature of the request-for-token, the kind of credentials required, the shape of the token response, and so on.