Why doesn't OAuth GenerateAccessToken for client_credentials raise a fault on error?

I'm using the following policy to generate an token for client_credentials:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OA-GenerateAccessToken-ClientCredentials">
    <DisplayName>OA-GenerateAccessToken ClientCredentials</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>GenerateAccessToken</Operation>
    <!-- This is in millseconds, so expire in 8 hours -->
    <ExpiresIn>28800000</ExpiresIn>
    <SupportedGrantTypes>
        <GrantType>client_credentials</GrantType>
    </SupportedGrantTypes>
    <!-- <Scope>request.formparam.scope</Scope> -->
    <GrantType>request.formparam.grant_type</GrantType>
    <GenerateResponse enabled="true"/>
    <GenerateErrorResponse enabled="false"/>
</OAuthV2>

If I pass bad client_id or client_secret, I get 401 Unauthorized with the following "text" response:

{"ErrorCode" : "invalid_client", "Error" :"Client credentials are invalid"}

But no fault gets raised. I want to catch the fault and change the response to follow my standard error response.

I noticed that if I set: <GenerateResponse enabled="true"/> a fault gets raised, but I don't get an OK response with an access_token on a successful request.

Changing <GenerateErrorResponse enabled="true"/> or false, doesn't have an affect on the error response.

This seems like strange behavior.

3 4 1,015
4 REPLIES 4

hadleena
Participant III

Hi @Kurt Kanaskie,

I guess what you were really trying to mean in your question was that while you tried to set:

<GenerateResponse enabled="false"/> fault gets raised, but you don't get an OK(success response in case of valid scenario) response.

I noticed the same too.

I get a fault raised when <GenerateResponse enabled="false"/>

{"fault":{"detail":{"errorcode":"oauth.v2.InvalidClientIdentifier"},"faultstring":"Invalid client identifier {0}"}}

To get the payload for success response, as a workaround you can try to use an assign message policy in the response flow to get the required details of the generated token. Something like below will give you the desired response for success scenario:

<AssignMessage async="false" continueOnError="false" enabled="true" name="AssignTokenResponse">
    <DisplayName>AssignTokenResponse</DisplayName>
    <Properties/>
    <Set>
        <Payload contentType="application/json" variableSuffix="%" variablePrefix="$">
            {
           "access_token" : "$oauthv2accesstoken.generate-token.access_token%",
           "status" : "$oauthv2accesstoken.generate-token.status%",
           "expires_in" : "$oauthv2accesstoken.generate-token.expires_in%"
            }
            </Payload>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo type="response" transport="http" createNew="false"/>
</AssignMessage>

where generate-token is the name of my OAuth policy.

For "GenerateErrorResponse", I can see that it has no effect on the error response like you mentioned 🙂

That would work, however, I'd rather Raise Fault in case of error.

Yes @Kurt Kanaskie. You can customize the fault message or raise fault with the help of the fault message you receive from apigee. I was just trying to explain an option that you could use to get the fault details as well as the success response when the value of GenerateResponse is 'false' 🙂

The approach I decided on is to detect the OAuth policy failure and then Raise Fault. It has to be done in the response flow because once the OAuth policy executes, the flow transitions to the response flow.

This worked:

<Flow name="Token - Client Credentials">
    <Description/>
    <Request>
        <Step>
            <Name>OA-GenerateAccessToken-ClientCredentials</Name>
        </Step>
    </Request>
    <Response>
        <Step>
            <Condition>oauthV2.OA-GenerateAccessToken-ClientCredentials.failed = true</Condition>
            <Name>RF-InvalidClientCredentials</Name>
        </Step>
    </Response>
    <Condition>(request.verb = "POST") and (proxy.pathsuffix MatchesPath "/token") and (request.formparam.grant_type = "client_credentials") and (request.header.authorization is null)</Condition>
</Flow>