Invalid Authorization Code error using OAuth 2.0 policy with external authorization

I am developing a proxy in order to integrate Apigee with Azure.(External Authorization with auth code grant type)

I have similar issue like this thread - https://community.apigee.com/questions/36580/invalid-authorization-code-error-using-oauth-20-po.html

I made sure that policy has all the specified parameters as mentioned in the above thread's solution.

But still giving me same error.Please help .

The Oauth policy looks like below :

<OAuthV2 name="Oauth2.GenerateAccessToken"> 
  <DisplayName>Set OAuth Tokens</DisplayName> 
  <ExternalAuthorization>true</ExternalAuthorization> 
  <Operation>GenerateAccessToken</Operation> 
  <ClientId>request.formparam.client_id</ClientId> 
  <ReuseRefreshToken>false</ReuseRefreshToken> 
  <SupportedGrantTypes> 
    <GrantType>authorization_code</GrantType> 
  </SupportedGrantTypes> 
  <GrantType>request.formparam.grant_type</GrantType> 
  <GenerateResponse enabled="true"> 
    <Format>FORM_PARAM</Format> 
  </GenerateResponse> 
  <ExternalAccessToken>externalAccessToken</ExternalAccessToken>
  <StoreToken>true</StoreToken> 
  <Tokens/> 
</OAuthV2>
0 7 892
7 REPLIES 7

I would like to know more about what you're hoping to do. Do you have a sequence diagram that shows the interactions between client, Apigee, and Azure? What is Azure's role? I can guess you mean Azure Active Directory, which means Azure acts as an identity provider.

But Azure can do the 3-legged dance by itself. So What role does Apigee play, then?

There are lots of ways Apigee can be used with OpenID Connect providers. There's not "one true way". Different customers have different requirements and desires.

So please elaborate on what you are trying to accomplish, and we'll see if we can help you.


Just for some background, Apigee includes support for OAuth2 "authorization code" flows. Here is a hands-on lab exercise showing what that would look like. The notes for that exercise include a sequence diagram, and a discussion of what pieces connect with what. This example does not rely on Azure for identity; there's a mock IDP in this example.

@Dino :

Thanks for your quick response, Please refer the sample sequence diagram. So , as per the sequence I am able to get the ID token, access token and trying to validate it but OAuthV2 policy is failing with 400.

{"Error":"Invalid Authorization Code","ErrorCode":"invalid_request"}

Image for post

The OpenID Provider in this case is ... Azure AD?

Which actor is Apigee? The "Relying party"?

There is something not quite aligned, I think. You said

as per the sequence I am able to get the ID token, access token and...

If you (the Relying Party) are able to get the ID token and access token, then the OIDC flow is complete. That step falls AFTER the verification of the authorization code to the OpenID Connect provider. So there is no need to check any authorization code, if you already have the ID token and access_token.

trying to validate it but OAuthV2 policy is failing with 400.

Not clear which token you are trying to validate. I suppose the ID token is a JWT, since this is an OIDC flow. You can validate a JWT with VerifyJWT policy in Apigee, and you cannot validate a JWT with the OAuth2 policy. though... in the flow depicted in this diagram, there is not much need to validate the token, since the Relying Party JUST GOT the token from the OpenID Connect provider. There's no real need to validate it RIGHT THEN. It came directly from the provider, it's going to be valid.

Then there is the other token, the access token. In some cases this is a JWT, in which case, the same applies. 1. You can validate it with the VerifyJWT policy, not the OAuth2 policy, and 2. you don't need to validate it AT THAT TIME. Some OIDC providers issue opaque access_tokens, and in that case, statement #1 does not apply, but #2 does apply.

In no case can you expect to use the OAuth2 policy to verify or validate a token (JWT or opaque) that you obtained from a third-party OIDC provider, like Azure AD. The OAuthV2 policy in Apigee is a multi-purpose policy. Check the documentation for full details. It CAN be used for

  • generating a new opaque token
  • validating/verifying an existing opaque token that was issued by Apigee
  • generating an authorization code (for use within authorization code grant)
  • refreshing an access_token

It IS possible to import an opaque token that has been generated by an external system, like Azure, into Apigee. In which case, you *could* use the OAuthV2 policy to verify that token. It seems like you're trying to do that, judging from the policy configuration you showed, which has the ExternalAccessToken element.

But if you use the policy that way, for authorization_code grant.... then... Apigee checks the authorization code, and the code must be one that Apigee itself has generated! If you get an authorization code from Azure, that's not known by Apigee. Therefore using OAuthV2/GenerateAccessToken with GrantType authorization_code, passing in a code that is generated by Azure, will not work. It will always fail with 400 "invalid authorization code". Apigee doesn't know about Azure's codes.

I think you can avoid the entire issue though; the authorization code is there to support the 3-legged dance, which .... at this point is complete. You don't need authorization_code grant type in Apigee. You used the authorization_code grant type with Azure (OIDC provider) but for importing the Azure-generated token into Apigee, you can use client_credentials grant_type and attach the user attributes to that Apigee-generated token.

That's what I would do.

<OAuthV2 name="Oauth2.ImportAccessToken"> 
  <ExternalAuthorization>true</ExternalAuthorization> 
  <Operation>GenerateAccessToken</Operation>
  <!--
    ExpiresIn, in milliseconds. The ref is optional. The explicitly 
    specified value is the default, when the variable reference 
    cannot be resolved. eg,
      2400000 = 40 minutes
      3600000 = 60 minutes
  -->
  <ExpiresIn ref='flow.variable'>1800000</ExpiresIn>

  <ClientId>request.formparam.client_id</ClientId> 
  <ReuseRefreshToken>false</ReuseRefreshToken> 
  <SupportedGrantTypes> 
    <GrantType>client_credentials</GrantType> 
  </SupportedGrantTypes> 
  <GrantType>request.formparam.grant_type</GrantType> 
  <GenerateResponse enabled="true"/> 
  <ExternalAccessToken>externalAccessToken</ExternalAccessToken>
  <StoreToken>true</StoreToken>
  <Attributes>
    <Attribute name='username' ref='flow.variable' display='true'/>
  </Attributes>

</OAuthV2>

You need to set request.formparam.grant_type to client_credentials, and also set the Authorizationheader with the right basic auth value, prior to invoking this policy, in order for it to work.

The result will be the token issued by Azure, will be imported into Apigee, so that in the future, an OAuthV2/VerifyAccessToken will work with that opaque Azure-generated token.

@Dino Thank you for the detailed explaination.

Well I can not use client-credentails grant type in this scenario as I also need refresh token.

I understand that. And you've already used the authz code with the IDP. I wrote a whole bunch, maybe you can .... react in a little more detail to the suggestions and observations and comments I provided.

I am facing refresh token generation issue.

Step 1:

AccessToken getting generated and RefreshToken as well.
Step 2: 

Using refresh token we are again generating accesstoken and refreshtoken using auhtcode GT.
Step 3:

After successful generation of refreshtoken 2 times, I am getting "Invalid Auth code" even I have not made any change in this.

Yours seems like a completely new question. Please ask a new question, and someone will try to answer it.

There is a button labeled "ask a question" in the upper right.