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! Go to 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>
...
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!