Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
A digital padlock representing the unsupported_grant_type Apigee error resolution for secure Salesforce API integrations.
Integration

unsupported_grant_type: Fixing Apigee JWT Integration

The unsupported_grant_type error in Apigee usually comes down to how the OAuthV2 policy reads request headers against body parameters. Here is how to map the JWT across and override the standard form-data requirement.

Key takeaways Apigee's OAuthV2 policy requires grant_type in the request body. If your architecture uses headers, transform them into form parameters with an AssignMessage policy. Define the urn:ietf:params:oauth:grant-type:jwt-bearer string within the <SupportedGrantTypes> block of your policy. Run your transformation policy in the PreFlow, before the OAuthV2 policy is invoked. Validate the JWT signature with a dedicated VerifyJWT policy before you use the token to generate an access token. You get better security, and a clearer error when something is wrong.

Understanding the conflict

Integrate Salesforce with Apigee over the OAuth 2.0 JWT Bearer flow and sooner or later you meet the unsupported_grant_type error. On the Salesforce side we are used to sending the grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer payload in a standard form-encoded body. When an architectural requirement forces a custom x-access-token header instead, or the gateway is configured a particular way, Apigee's standard OAuthV2 policy fails to parse the incoming request.

The error fires because the OAuthV2 policy looks for the grant_type parameter inside the body of the POST request and nowhere else. If your client sends that data in a header, or the Apigee proxy strips form-encoded parameters in favor of header-based auth, the policy has no way to work out how to handle the token exchange, and it defaults to an unsupported state.

Anatomy of the JWT request failure

In a standard Salesforce-to-Apigee flow, the request usually looks like this:

POST /oauth/token HTTP/1.1
Host: your-org.apigee.net
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=eyJhbGci...[JWT_TOKEN]

Once the x-access-token header is in play, developers tend to pass the assertion there instead of in the body. The Apigee policy, specifically the OAuthV2 operation GenerateAccessToken or ValidateAccessToken, is hard-wired to look for specific query parameters or form fields. When grant_type is missing from the location it expects, the policy marks the grant type itself as unsupported.

Correcting the policy flow

The fix is to intercept the request before it hits the OAuthV2 policy. We use an AssignMessage policy to transform the incoming headers into the form parameters the policy expects.

Step 1: Create an AssignMessage policy

This policy pulls the token out of your x-access-token header and maps it to the assertion parameter that Apigee's underlying flow expects.

<AssignMessage name="AM-MapHeaderToForm">
    <AssignTo createNew="false" transport="http" type="request"/>
    <Set>
        <FormParams>
            <FormParam name="grant_type">urn:ietf:params:oauth:grant-type:jwt-bearer</FormParam>
            <FormParam name="assertion">{request.header.x-access-token}</FormParam>
        </FormParams>
    </Set>
    <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</AssignMessage>

Step 2: Update the Proxy Endpoint

In your Proxy Endpoint, run this policy before the OAuthV2 policy. By the time the OAuth policy executes, the grant_type is physically present in the request body, whatever the client actually sent.

<PreFlow name="PreFlow">
    <Request>
        <Step>
            <Name>AM-MapHeaderToForm</Name>
        </Step>
        <Step>
            <Name>OAuthV2-GenerateToken</Name>
        </Step>
    </Request>
</PreFlow>

Troubleshooting the OAuthV2 policy configuration

If the error survives the form-parameter mapping, look at the OAuthV2 policy configuration itself. The usual culprit is the SupportedGrantTypes element.

Your policy has to allow the JWT bearer grant type explicitly. Leave that element out or misconfigure it, and Apigee rejects the request by default.

<OAuthV2 name="OAuthV2-GenerateToken">
    <Operation>GenerateAccessToken</Operation>
    <SupportedGrantTypes>
        <GrantType>urn:ietf:params:oauth:grant-type:jwt-bearer</GrantType>
    </SupportedGrantTypes>
    <GenerateResponse enabled="true"/>
</OAuthV2>

Check too that the grant_type you send matches the string defined in your SupportedGrantTypes exactly. Any variation in character case or whitespace will trigger the unsupported_grant_type error.

Best practices for secure JWT handling

When working with JWTs in Apigee and Salesforce, avoid logging the full token in your Apigee Trace tool or system logs.

  • Store sensitive secrets in a KeyValueMap, or set them with an AssignMessage policy, rather than hardcoding them in policies.
  • Always include a VerifyJWT policy before the OAuthV2 policy, so you know the token has not been tampered with and the iss (issuer) matches your Salesforce Connected App consumer key.
  • Cache the validated tokens with Apigee's internal caching, so you are not revalidating against the identity provider on every call.
Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment