Welcome to Apigee community.
For your usecase there are different ways one can achieve but one way you can do is drop below policies in postflow - https://docs.apigee.com/api-platform/fundamentals/what-are-flows
High level:
0.Create a cache by name OAuthAccessToken with what ever oauth token expiry time.
https://docs.apigee.com/api-platform/cache/manage-caches-environment
1.Perform lookup cache first (first time it will be cache miss) -(https://docs.apigee.com/api-platform/reference/policies/lookup-cache-policy)
if cache fails then
a.invoke the actual oauth endpoint using service callout.(https://docs.apigee.com/api-platform/reference/policies/service-callout-policy)
b.extract the Response. (https://docs.apigee.com/api-platform/reference/policies/extract-variables-policy)
c.populate to the cache.(https://docs.apigee.com/api-platform/reference/policies/populate-cache-policy)
if cache hit’s (meaning lookup is successful) then it will skip rest of the steps (like invoke oauth endpoint, extract & populate cache)
2.Either case you will have the access token to backend rest api using Assign message in the target flow. – didn’t add it assuming you are aware of it.
Just FYI:
Assuming you are aware of CORS - https://docs.apigee.com/api-platform/develop/adding-cors-support-api-proxy (which is added to the conditional flow)
<PostFlow name="PostFlow">
<Request>
<Step>
<Name>LC-OAuthToken</Name>
<Condition>request.verb != "OPTIONS"</Condition>
</Step>
<Step>
<Name>SC-OAuthTokenRequest</Name>
<Condition>request.verb != "OPTIONS" and lookupcache.LC-OAuthToken.cachehit = false</Condition>
</Step>
<Step>
<Name>EV-OAuthToken</Name>
<Condition>request.verb != "OPTIONS" and tokenResponse.content != null"</Condition>
</Step>
<Step>
<Name>PC-OAuthToken</Name>
<Condition>request.verb != "OPTIONS" and lookupcache.LC-OAuthToken.cachehit = false</Condition>
</Step>
</Request>
</PostFlow>
Individual Policy information:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LookupCache async="false" continueOnError="false" enabled="true" name="LC-OAuthToken">
<DisplayName>LC-OAuthToken</DisplayName>
<CacheResource>OAuthAccessToken</CacheResource>
<AssignTo>tokenResponse.content</AssignTo>
<Scope>Exclusive</Scope>
<CacheKey>
<KeyFragment>access_token</KeyFragment>
</CacheKey>
</LookupCache>
Make sure you read below private.* values from encrypted KVM in pre-flow.
Below is the service callout to invoke authorization server token endpoint.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="false" continueOnError="false" enabled="true" name="SC-OAuthTokenRequest">
<DisplayName>SC-OAuthTokenRequest</DisplayName>
<Properties/>
<Request clearPayload="true" variable="OAuthTokenRequest">
<Set>
<FormParams>
<FormParam name="grant_type">{private.grantType}</FormParam>
<FormParam name="client_id">{private.clientId}</FormParam>
<FormParam name="client_secret">{private.clientSecret}</FormParam>
</FormParams>
<Headers>
<Header name="Content-Type">application/x-www-form-urlencoded</Header>
</Headers>
<Verb>POST</Verb>
</Set>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</Request>
<Response>tokenResponse</Response>
<HTTPTargetConnection>
<Properties/>
<URL>https://{private.tokenUrl}</URL>
</HTTPTargetConnection>
</ServiceCallout>
Extracting the response from the service callout (check the tokenResponse.content)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="EV-OAuthToken">
<DisplayName>EV-OAuthToken</DisplayName>
<Properties/>
<JSONPayload>
<Variable name="access_token">
<JSONPath>$.access_token</JSONPath>
</Variable>
<Variable name="token_type">
<JSONPath>$.token_type</JSONPath>
</Variable>
<Variable name="expires_in">
<JSONPath>$.expires_in</JSONPath>
</Variable>
</JSONPayload>
<Source clearPayload="false">tokenResponse.content</Source>
</ExtractVariables>
Now populate the cache
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PopulateCache async="false" continueOnError="false" enabled="true" name="PC-OAuthToken">
<DisplayName>PC-OAuthToken</DisplayName>
<CacheResource>OAuthAccessToken</CacheResource>
<Source>tokenResponse.content</Source>
<Scope>Exclusive</Scope>
<CacheKey>
<KeyFragment>access_token</KeyFragment>
</CacheKey>
<ExpirySettings>
<TimeoutInSec>890</TimeoutInSec>
<!--example Token expires in 900 sec you can provide little lower time to be safer side-->
</ExpirySettings>
</PopulateCache>
Good Luck