How to Validate an Externally-generated OAuth token

Not applicable

Hi,

I want to know how to validate the token generated by a third party application in APIGEE Edge? (the token to be verified is not a JWT token)


This is how client is making the request(s):

Step 1: to get Access Token

Client will send request to the proxy created in APIGEE edge. Request contains username, password, client id, client secret and grant type (password). Target endpoint is Internal Oauth server.
And response contains access_token, token_type, refresh_token, expiry details etc..

Step 2: to call the actual endpoint

Client will send the request to another proxy in APIGEE and pass the token which received from the previous request as Bearer token in Authorization header.
Here target endpoint is API which is sending the response request by the client.


Now, I want to know how I can validate the token in Step 2 where token is received from the Internal Oauth server in Step 1. What are the policies to be added and where to add?

Solved Solved
0 11 4,023
1 ACCEPTED SOLUTION

Former Community Member
Not applicable

When you perform step 1, you might want to also use Apigee' OAuth policy and store that token. Please refer to this link on how that can be done (http://docs.apigee.com/api-services/content/use-third-party-oauth-system). The policy has three options you'd be interested in - set external auth server to true, store external access to true and store refresh token to true.

With this step, Apigee stores (and manages going forward) the access token generated by the external auth server. Since it has also stored the refresh token, it can also renew access tokens. Finally, perhaps most importantly, you can validate the access token without having to leave Apigee.

In step 2, use the Apigee Oauth policy (with default config) to validate the access token.

NOTE: To complete the process, you will also need to import the client id and secret (aka consumer key and secret) from the external auth server to Apigee. You can read about that here: http://docs.apigee.com/developer-services/content/import-existing-consumer-keys-and-secrets

View solution in original post

11 REPLIES 11

Former Community Member
Not applicable

When you perform step 1, you might want to also use Apigee' OAuth policy and store that token. Please refer to this link on how that can be done (http://docs.apigee.com/api-services/content/use-third-party-oauth-system). The policy has three options you'd be interested in - set external auth server to true, store external access to true and store refresh token to true.

With this step, Apigee stores (and manages going forward) the access token generated by the external auth server. Since it has also stored the refresh token, it can also renew access tokens. Finally, perhaps most importantly, you can validate the access token without having to leave Apigee.

In step 2, use the Apigee Oauth policy (with default config) to validate the access token.

NOTE: To complete the process, you will also need to import the client id and secret (aka consumer key and secret) from the external auth server to Apigee. You can read about that here: http://docs.apigee.com/developer-services/content/import-existing-consumer-keys-and-secrets

Thanks Srinandan for your response.


Step1: I created the "AssignMessage" and "OAuthV2" policy in the response step of the pre flow.
Step2: Created "OAuthV2" for token validation
<OAuthV2 async="false" continueOnError="false" enabled="true" name="verify-oauth-v2-access-token">
<DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
<Operation>VerifyAccessToken</Operation>
</OAuthV2>

Also I followed steps in http://docs.apigee.com/developer-services/content/import-existing-consumer-keys-and-secrets
But out of 2 steps, I was able to create consumer keys-and-secrets but failed in Step 2 associate keys-and-secrets with product. And I am getting 404 error here (I verified that all the param looks fine in the request)

Then I try to access the proxies. I was able to get the token from the Internal OAuth server, but failed during the step2
"faultstring": "Invalid Access Token"

You didn't mention the kind of token to be verified.

You may be aware of the JWT standard. JWT are tokens that can be verified by any party who has access to the public key, or the shared key if using symmetric encryption.

If your OAuth token dispenser is delivering JWT, then Apigee Edge can simply verify them according to standard JWT practice. **EDIT** - here is a good example of an API Proxy that verifies JWT. You will need to add in the Java callout policy available on that github repo, and configure it like so:

<JavaCallout name='JWT-Parse-RS256'>
  <Properties>
    <Property name="algorithm">RS256</Property>
    <Property name="jwt">{request.formparam.jwt}</Property>
    <!-- public-key used only for algorithm = RS256 -->
    <Property name="public-key">
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtxlohiBDbI/jejs5WLKe
    Vpb4SCNM9puY+poGkgMkurPRAUROvjCUYm2g9vXiFQl+ZKfZ2BolfnEYIXXVJjUm
    zzaX9lBnYK/v9GQz1i2zrxOnSRfhhYEb7F8tvvKWMChK3tArrOXUDdOp2YUZBY2b
    sl1iBDkc5ul/UgtjhHntA0r2FcUE4kEj2lwU1di9EzJv7sdE/YKPrPtFoNoxmthI
    OvvEC45QxfNJ6OwpqgSOyKFwE230x8UPKmgGDQmED3PNrio3PlcM0XONDtgBewL0
    3+OgERo/6JcZbs4CtORrpPxpJd6kvBiDgG07pUxMNKC2EbQGxkXer4bvlyqLiVzt
    bwIDAQAB
    -----END PUBLIC KEY-----
    </Property>
    <!-- claims to verify -->
    <Property name="claim_iss">http://dinochiesa.net</Property>
    <Property name="claim_shoesize">8.5</Property>
  </Properties>
  <ClassName>com.apigee.callout.jwtsigned.JwtParserCallout</ClassName>
  <ResourceURL>java://jwt-signed-edge-callout.jar</ResourceURL>
</JavaCallout>

Note: To verify an externally-generated JWT, you do not need to import client_ids or client_secrets into Apigee Edge. JWT are self-verifiable. There is no need for Apigee Edge to "know" the client_id you used when your client app contacted the external token issuer. If you want to use Apigee Edge to verify an externally-generated token that is not a JWT, then you DO need to import the client_id and client_secret.


There are some options for configuring this policy. For example if the public key changes, and is available at an external HTTP URL, then you will need to augment this policy with a ServiceCallout to retrieve the public key, then specify the variable that holds the PKCS8-PEM encoded public key like so:

<Property name="public-key">{variable_holding_public_key}</Property>

If the JWT uses HS256, then you need to specify the secret key instead of the public key.

Also you will want to modify the claims you are verifying. The policy automatically verifies the issued-at time and the not-before-time (if it exists) and the expiry time.

There is more information in the Readme on that github repo.


On the other hand if the token is an opaque token, then you will need one of the following:

  1. contact the token issuer for each verification of the token, probably via ServiceCallout
  2. "import" the token into Apigee Edge at issue time and use the standard VerifyAccessToken OAuth2 policy.

Which option you choose depends on your requirements.

Thanks for the response, token to be verified is JWT token

ok, I've extended my answer.

hmm, ok, NO, the token is not a JWT. So my answer is irrelevant. Except for the last part, beginning "On the other hand".

I was trying to store to token in Apigee Edge at the time of Token generation. Here are the steps that I have followed.

Step 1: (Token generation call)

In the response section of pre flow, I have added the policies
a. <AssignMessage>, here I set "oauth_external_authorization_status" to true

b. <OAuthV2>

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuth_External">
<DisplayName>OAuth_External</DisplayName>
<ExternalAuthorization>true</ExternalAuthorization>
<ExternalAccessToken>{request.formparam.access_token}</ExternalAccessToken>
<Operation>GenerateAccessToken</Operation>
<GenerateResponse enabled="true">
<Format>FORM_PARAM</Format>
</GenerateResponse>
<StoreToken>true</StoreToken>
<SupportedGrantTypes>
<GrantType>password</GrantType>
</SupportedGrantTypes>
<Tokens/>
</OAuthV2>


Step 2: Second call with the Token, used <OAuthV2> policy to validate the token

<OAuthV2 async="false" continueOnError="false" enabled="true" name="verify-oauth-v2-access-token">
<DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
<Operation>VerifyAccessToken</Operation>
<AccessTokenPrefix>Bearer</AccessTokenPrefix>
</OAuthV2>

Also imported Client Id and Secret, followed steps (http://docs.apigee.com/management/apis/post/organizations/%7Borg_name%7D/developers/%7Bdeveloper_email_or_id%7D/apps/%7Bapp_name%7D/keys/create)

But as I mentioned in my comment above

token is "Successfully" validated at Apigee but validation fails at the end resource as Apigee is generating the token. But if I am changing <GenerateResponse enabled="true"> in <OAuthV2> policy to "false". Token validation fails at Apigee as Apigee cannot validate the token in this case.

Did I miss something here or any issue in the policy configuration?

Your question isn't entirely consistent. You have said in a separate comment that the token to be verified is a JWT. But then you also stated that there is an access_token, a refresh_token, and so on. These are not consistent. USually that latter set of information is not included in a JWT.

So can you please clarify the question you are asking? Rather than "describing" the token, can you show an example?

Not applicable

The response from the Internal OAUTH server looks similar to this:

{
"access_token": "access_token",
"token_type": "bearer",
"expires_in": 299,
"refresh_token": "refresh_token",
"userName": "userName",
"client_id": "client_id",
".issued": "Wed, 21 Dec 2016 23:16:05 GMT",
".expires": "Wed, 21 Dec 2016 23:21:05 GMT"
}
In my usecase, I have to validate the token at two points. Initially at Apigee end and another validation happens at the end resource

I am using following OAUTH policy in the response flow (during token generation call).

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuth_External">
<DisplayName>OAuth_External</DisplayName>
<ExternalAuthorization>true</ExternalAuthorization>
<ExternalAccessToken>{request.formparam.access_token}</ExternalAccessToken>
<Operation>GenerateAccessToken</Operation>
<GenerateResponse enabled="true">
<Format>FORM_PARAM</Format>
</GenerateResponse>
<StoreToken>true</StoreToken>
<SupportedGrantTypes>
<GrantType>password</GrantType>
</SupportedGrantTypes>
<Tokens/>
</OAuthV2>

Response send back to client and when client make api call with the Bearer token, token is "Sucessfully" validated at Apigee but validation fails at the endresource.

But if I am changing <GenerateResponse enabled="true"> to "false". Token valiation fails at Apigee.

When I checked the response with both the settings, there are some differences. Also length of the token is small in the former case. It looks like Apigee is generating the token in the former case and Internal Oauth server is generating the latter case. As I dont want to regenerate the token in APigee. How can I validate the token at apigee?

OK, that's not a JWT. See my answer below, beginning "on the other hand," . That's how you validate external tokens.

Not applicable

@Dino

I was trying to store to token in Apigee Edge at the time of Token generation. Here are the steps that I have followed.

Step 1: (Token generation call)

In the response section of pre flow, I have added the policies
a. <AssignMessage>, here I set "oauth_external_authorization_status" to true

b. <OAuthV2>

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuth_External">
<DisplayName>OAuth_External</DisplayName>
<ExternalAuthorization>true</ExternalAuthorization>
<ExternalAccessToken>{request.formparam.access_token}</ExternalAccessToken>
<Operation>GenerateAccessToken</Operation>
<GenerateResponse enabled="true">
<Format>FORM_PARAM</Format>
</GenerateResponse>
<StoreToken>true</StoreToken>
<SupportedGrantTypes>
<GrantType>password</GrantType>
</SupportedGrantTypes>
<Tokens/>
</OAuthV2>


Step 2: Second call with the Token, used <OAuthV2> policy to validate the token

<OAuthV2 async="false" continueOnError="false" enabled="true" name="verify-oauth-v2-access-token">
<DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
<Operation>VerifyAccessToken</Operation>
<AccessTokenPrefix>Bearer</AccessTokenPrefix>
</OAuthV2>

Also imported Client Id and Secret, followed steps (http://docs.apigee.com/management/apis/post/organizations/%7Borg_name%7D/developers/%7Bdeveloper_email_or_id%7D/apps/%7Bapp_name%7D/keys/create)

In my usecase, token validation happens at two points. Initially at Apigee end and another validation happens at the end resource


But as I mentioned in my comment above

with the above policy configuration token is "Successfully" validated at Apigee but validation fails at the end resource as Apigee is generating the token. But if I am changing <GenerateResponse enabled="true"> in <OAuthV2> policy to "false". Token validation fails at Apigee as Apigee cannot validate the token in this case.

Did I miss something here or any issue in the policy configuration?