Proxy a Target Server secured by OAuth 2.0

Not applicable

I am building an application that makes calls to various 3rd party APIs, all secured via different methods (api key, Basic, OAuth, etc). I want to secure my application using Apigee OAuth implementation so the client only has to deal with a single authentication scheme. How do I build a proxy that when called will get an OAuth token if needed or refresh an existing one? Clearly I don't want to request a new token on every call so I need a way to check if a token is already generated, then if it is test to see if it's valid (target server supports this), then if it's valid use it, if not get a new one. Are there any examples of a proxy that implements this scheme?

Thanks,

Chad

1 6 2,114
6 REPLIES 6

Not applicable

Hello @Chad Dalton,

Can you please let me know, if the following understand is correct?

1. Consume an access token generation api proxy with appropiate grant_type and credentials. This API proxy would give you the refresh token and access token.

2. Validate the access token in another proxy flow by passing the access token.

2. a. If it is NOT expired, access the backend.

2. b. If it is expired, then call the refresh token endpoint with the earlier generated refresh token and get a new refresh token and access token.

3. Continue accessing the backend with the new access token.

If my understanding is correct, then yes, this can be achieved using two separate api proxies (one for generation and anther for validation of access tokens). You need to use Generate Access Token, Refresh Access Token and Validate Access Token operations of Apigee's OOB OAuth V2 policy.

But then I do not understand what do you mean by "Clearly I don't want to request a new token on every call so I need a way to check if a token is already generated, then if it is test to see if it's valid (target server supports this), then if it's valid use it, if not get a new one.".

My question is if the token is not valid but still we are going to generate a new one, then the whole purpose of Apigee Layer Authentication becomes use less.

OK let me be a little clearer, I am using the Apigee oauth to secure this proxy, that's working, so assume we are authenticated by Apigee to this proxy and my target is a 3rd party endpoint also secured by OAuth I want to store the required credentials for this 3rd party endpoint in lets just go with KeyValueMap for now. So in my proxy flow, that has already made it past the Apigee OAuthV2 step, I want to pull my 3rdparty bearer token out of my env variables (3rdpartybearertoken) for the 3rd party endpoint. If that variable does not exist I want to call the auth method of my 3rd party endpoint (3rdparty/auth) to get a new bearer token and refresh token. Once I have that continue the flow and store this token in an env variable (3rdpartybearertoken/3rdpartyrefreshtoken). Then in a subsequent call to my proxy the bearer token will exist, so next step is to verify it's still valid so call a method on the 3rd party endpoint to test if its good (3rdparty/authtest). If I get a 200, make the call using the 3rdpartybearertoken if it's not, call 3rdparth/auth again and then make the call. I'm not sure why i'd need multiple proxies to accomplish this other than the apigee oauth call and my 3rd party endpoint proxy that contains the logic above.

So basically I have 2 levels of OAuth going on here, one controlled by Apigee authenticating my proxy and one controlled by my proxy accessing the backend or 3rd party endpoint. I want to handle all the /auth /authtest 'stuff' in the proxy.

OK. Now its clear to me. In this case, you do not need 2 proxies, but a single one is enough.

Ok. Do you have any examples of this? Currently I'm trying this with Conditions and ServiceCallouts.

Yes, I think using Conditions and ServiceCallout policies is probably appropriate. I would not use a KeyValueMap, but rather a cache to store the token. Also, there is an issue of ownership for the token for the 3rd party. Do all inbound requests regardless of the identity of the caller use (share) the same 3rd party token? Or do you need to manage multiple tokens for that 3rd party service concurrently. But let's break it down.

  • the request call arrives
  • VerifyAccessToken - to verify the inbound OAuth token (issued by Apigee).
  • LookupCache policy to retrieve the 3rd party token . The cache key you use can be composite, and *may* include a component that refers to the identity of the caller.
  • ServiceCallout policy gated by a Condition, testing the value of the 3rd party token retrieved from cache. The response of the service callout will include a fresh token, as well as an expiry of said token.
  • An ExtractVariables policy (or JavaScript) gated by the same condition. This to extract the token and expiry from the JSON response.
  • PopulateCache policy gated by the same Condition. The item TTL should use the expiry time of the retrieved token!!
  • AssignMessage to insert the 3rd party token into the correct place for the message to be sent to the target
  • Then the proxy calls the target.
  • The response flows back through Apigee Edge.

There is one other twist. The ServiceCallout of course is a POST to a /token endpoint for the 3rd party service. That ServiceCallout needs to send *credentials* for the third party, which are Secrets. Therefore, prior to the ServiceCallout you need to retrieve those secrets from the encrypted KVM, or the Vault in some way. The KVM Get should also be gated by the same Condition.

@Dino Very helpful, I have everything you laid out working except,

  • ServiceCallout policy gated by a Condition, testing the value of the 3rd party token retrieved from cache. The response of the service callout will include a fresh token, as well as an expiry of said token.

How can I add a condition to the ServiceCallout? I am able to make the callout, get a new token, save to cache, then on subsequent calls query the cache and use the token. On calls when I do have a cache hit I am making the call to /authtest to check if the token is valid. What I need now is a way to handle any result that IS NOT a 200. How do I add a condition to the authtest servicecallout?

Thanks!!