refresh_token GrantType not working when combined with authorization_code GrantType

I have an OAuthV2 policy in my proxy, linked to a /token endpoint. Because I want to support exchanging both an authorization code, and a refresh token for an access token on the same endpoint, I deliberately haven't specified an Operation, but opted for 2 SupportedGrantTypes in stead: authorization_code and refresh_token. Here's the entire policy code:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="GenerateAccessToken">
    <DisplayName>GenerateAccessToken</DisplayName>
    <Properties/>
    <Attributes/>
    <ExternalAuthorization>false</ExternalAuthorization>
    <SupportedGrantTypes>
        <GrantType>authorization_code</GrantType>
        <GrantType>refresh_token</GrantType>
    </SupportedGrantTypes>
    <GenerateResponse enabled="true"/>
    <Tokens/>
    <RefreshToken>request.formparam.refresh_token</RefreshToken>
</OAuthV2>

The RefreshToken property shouldn't be necessary because that's supposed to be the default anyway, but I've added it just to make sure.

When using the authorization_code GrantType, everything is working fine. However, when I use the refresh_token GrantType, I receive the error: {"ErrorCode" : "invalid_request", "Error" :"Invalid Refresh Token"}.

To make sure the refresh token I'm using isn't actually invalid, I've created a separate endpoint, specifically with RefreshAccessToken as Operation. In this case, the exact same request (only different url) does result in a new access token. This is looking like:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="RefreshToken">
    <DisplayName>RefreshToken</DisplayName>
    <Properties/>
    <Attributes/>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>RefreshAccessToken</Operation>
    <SupportedGrantTypes/>
    <GenerateResponse enabled="true"/>
    <Tokens/>
</OAuthV2>

Does anyone have an idea why it doesn't work when combining the authorization_code and refresh_token grant types?

Solved Solved
0 3 142
1 ACCEPTED SOLUTION

Yes, 

You need two distinct operations for those things.

GenerateAccessToken for the initial generation.

RefreshAccessToken for the refresh. 

You can expose these on a single endpoint and use conditions to execute the right policy within Apigee. 

Something like this

<Flows>
 <Flow name='token'>
  <Condition>request.verb = "POST" and proxy.pathsuffix = "/token"</Condition>
  <Request>
   <Step>
    <Name>OAuthV2-GenerateAccessToken</Name>
    <Condition>request.formparam.grant_type = "authorization_code"</Condition>
   </Step>
   <Step>
    <Name>OAuthV2-RefreshAccessToken</Name>
    <Condition>request.formparam.grant_type = "refresh_token"</Condition>
   </Step>
   ...

View solution in original post

3 REPLIES 3

Yes, 

You need two distinct operations for those things.

GenerateAccessToken for the initial generation.

RefreshAccessToken for the refresh. 

You can expose these on a single endpoint and use conditions to execute the right policy within Apigee. 

Something like this

<Flows>
 <Flow name='token'>
  <Condition>request.verb = "POST" and proxy.pathsuffix = "/token"</Condition>
  <Request>
   <Step>
    <Name>OAuthV2-GenerateAccessToken</Name>
    <Condition>request.formparam.grant_type = "authorization_code"</Condition>
   </Step>
   <Step>
    <Name>OAuthV2-RefreshAccessToken</Name>
    <Condition>request.formparam.grant_type = "refresh_token"</Condition>
   </Step>
   ...

Thank you, that is working perfectly.

I thought it worked the way I tried because of this part of the documentation:

"If <Operation> is not specified, Edge looks at the list of <SupportedGrantTypes>. Only operations on those grant types will be successful. In other words, you can omit <Operation> if you specify a <GrantType> in the <SupportedGrantTypes> list."

Yes.  I feel your pain.  I would prefer it if the OAuthV2 policy were ... more than one policy and if there were fewer options!  I think it would be simpler to use. But in any case I'm glad it's working for you!