How to write the proper XML to get the access token

I've generated my jwt token, and now I want to send it to "https://oauth2.googleapis.com/token" to get back an access token.

The problem is that i can't properly construct the xml to make it work, if someone got any idea on what to do that would help me a lot.

Here is what i've already written :

<AssignMessage async="false" continueOnError="false" enabled="true" name="Assign-Message-bearer">
        <DisplayName>Assign Message-bearer</DisplayName>
        <Properties/>
        <Add>
            <Headers>
                <Header name="jwt-variable">{jwt-variable}</Header>
                <Header name="Content-type">application/x-www-form-urlencoded</Header>
            </Headers>
        </Add>
        <Set>
            <Headers/>
            <QueryParams/>
            <FormParams/>
            <Verb>POST</Verb>
            <Path/>
            <FormParams/>
        </Set>
        <OAuthV2 name="GetAccessToken">
            <Operation>GenerateAccessToken</Operation>
            <ExpiresIn>3600000</ExpiresIn>
            <SupportedGrantTypes>
                <GrantType>urn:ietf:params:oauth:grant-type:jwt-bearer</GrantType>
            </SupportedGrantTypes>
            <Assertion>{jwt-variable}</Assertion>
            <GenerateResponse/>
        </OAuthV2>
        <AssignVariable>
            <Name>target.url</Name>
            <Value>https://oauth2.googleapis.com/token</Value>
        </AssignVariable>
        <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
        <AssignTo createNew="false" transport="http" type="request"/>
    </AssignMessage>
0 5 1,325
5 REPLIES 5

No, that's not right.

It seems you have some confusion; you have combined the policy configuration for AssignMessage with the policy configuration for OAuthV2. But those are two distinct policies, they should be configured separately. You cannot insert the OAuthV2 element as a child within the AssignMessage policy.

The documentation for the various Apigee policies gives concrete examples of configuration.

In short,

  • If you want to generate an opaque access token, use OAuthV2 with Operation= GenerateAccessToken.
  • The AssignMessage policy is a multi-purpose policy useful for assigning headers, variables (like target.url), and so on.

You have a child element "Assertion" in the OAuthV2 policy... that looks not right. I don't know what you're intending with that element (maybe you could explain?), but it's not part of the documented configuration model for the OAuthV2 policy. Here is a specific working example of an OAuthV2 policy that generates tokens with client credentials grant type.

I want to get an access token from OAuth2 after generating my jwt token.

So I've deleted my Assign Message and changed it to a Service Callout thanks to Davissean, but i get an code error 500 (invalid request, "invalid impersonation sub field").

I really don't know why... Here is my Service Callout content :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout name="SC.ExchangeIdForAccessToken">
    <Request variable="accessTokenRequest">
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
        <Set>
            <FormParams>
                <FormParam name="assertion">{jwt-variable}</FormParam>
                <FormParam name="grant_type">urn:ietf:params:oauth:grant-type:jwt-bearer</FormParam>
            </FormParams>
        </Set>
    </Request>
    <Response>access_token.response</Response>
    <HTTPTargetConnection>
        <URL>https://oauth2.googleapis.com/token</URL>
    </HTTPTargetConnection>
</ServiceCallout>

And this is my flow :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Set-JWT-Secret</Name>
            </Step>
            <Step>
                <Name>Generate-JWT</Name>
            </Step>
            <Step>
                <Name>SC.ExchangeIdForAccessToken</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>
    <Flows/>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <HTTPProxyConnection>
        <BasePath>/gm-kite-svc-proxy</BasePath>
        <VirtualHost>secure</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>

This error is coming from Google OAuth APIs, not Apigee. This is a good sign, as it shows you have fixed your Apigee policies.

Taking a guess - it appears you are impersonating a different user when you generate your JWT, which is why you have this error. In general you dont want to generate the tokens from the ID token alone, as your Identity token expire.

The common approach is to download the credentials as a JSON file, then upload them to an Apigee KVM and use the shared flow I linked early to generate the token and manage caching.

For a working example of this, you can see this apigee-openlegacy example which uses tokens to access Google Cloud Run. You will be able to tweak lines 112 - 150 for your target.

Here is the code. HTH!

As Sean told you, the error you are seeing is not originating from Apigee. The error is coming from the Google OAuth token endpoint, and is telling you that the "sub" claim in the JWT that you have generated, is invalid.

It is not correct, according to the requirements from the Google token service.

As far as I know, the token dispensary requires a self-signed JWT with these claims: iss, aud, exp, and optionally scope. I am not aware that a "sub" claim is required; it's possible that any JWT with a "sub" claim will be rejected. OR, maybe there is a way to use "sub" to ask for impersonation powers, (this is not something I'm familiar with) and the Google token service is telling you "sorry, you don't have the rights to impersonate that subject."

Anyway check your JWT claims.

If I were debugging this, I would get it to work outside of Apigee first, and then convert that code into the Apigee form. Figure out the shape of the JWT you need just by using development tools and command-line gen of JWT, send it to the token endpoint with curl.... The dev/test loop will be much faster.

https://github.com/apigee/devrel/blob/main/references/gcp-sa-auth-shared-flow/sharedflowbundle/polic...

here is a working example of exactly what you are trying to do

if you are looking to generate GCP tokens from a service account, you can use this Shared Flow as is