Ana içeriğe geç

Getting a JWT Token from a Backend Application via API Call and Applying Cache

In this scenario, it will be explained how a JWT token expected by the backend is obtained from the backend application's token endpoint using the API Call policy on a REST API Proxy named Swagger PetStore, and how that token is configured to be reused through the cache mechanism.

Example Scenario:

  • The backend API expects an Authorization: Bearer <jwt> header on every request.
  • The token is obtained from a token (authentication) endpoint belonging to the backend application.
  • Calling the token service on every client request is undesirable in terms of both latency and load on the token service.
  • Therefore the token is obtained with the API Call policy; the response is cached and the same token is reused until it expires.

Solution:

An API Call policy added on the request pipeline in Apinizer makes a synchronous call to the token endpoint. The access_token value from the response is added to the Authorization header of the request that will go to the backend. On the Cache tab, Dynamic TTL is enabled so that TTL is calculated from the JWT exp claim (or from the expires_in field in the response); thus an expired token is not kept in cache.

The application steps of the scenario mentioned above are as follows;

  • The API Client sends a request to Apinizer.
  • Apinizer checks whether a valid token exists in cache.
    • Cache miss: An API Call is made to the backend token endpoint and the returned JWT is written to cache.
    • Cache hit: The token service is not called; the JWT in cache is used.
  • The obtained JWT is added to the Authorization header of the request going to the backend.
  • Apinizer sends the request to the Backend API.
  • The Backend API responds to Apinizer.
  • Apinizer responds to the API Client.
bilgi

In this scenario, https://auth.example.com/oauth/token is used as the sample token endpoint. In your own environment you must use the real token URL, client credentials, and grant type of your backend application. For field-level details of the API Call policy, see the API Call page.

1) Creating the API Proxy

In this scenario, a REST API named Swagger Petstore (https://petstore.swagger.io) will be used.

First, this address must be defined as an API Proxy.

For this, click the API Proxies option under the API Gateway menu.

API Proxies Menu

Since no proxy definition has been made yet on the opened page, the text No records found! appears.

Click the Add API Proxy button in the top right corner and start creating a new API Proxy.

Create Button

In this section, the type of the API Proxy to be created must be selected.

Since the type of API used in this scenario will be Swagger 2.X, this type is selected.

Click Enter URL to switch to the screen where the address of the API to be used will be entered.

API Spec Type Selection

As shown in the image below, enter the address to be accessed in the URL field and click the Parse button.

URL Entry Screen

After the Parse operation, the screen shown below appears.

Screen After Parse

API Proxy settings can be configured on this screen. For detailed information about these settings, see the API Proxy Creation documentation.

The settings of the API Proxy to be used in this scenario are as shown below.

API Proxy Settings

After saving, click the Develop tab on the opened page.

Develop Tab

The endpoints of the REST API are listed here.

bilgi

With the All expression above these endpoints, policies to be added can be applied to all endpoints. In this scenario the API Call policy will be added on the request pipeline via All.

Deploy the created API Proxy by clicking the Deploy button in the upper right area.

Deploy Button

2) Creating Variables to Carry the Token Value

Variable definitions are required to read the access_token field from the token response and write this value to the backend request header.

For this, click the Variables option under API Gateway in the navbar.

Variables Menu

On the opened screen, click the Create button in the top right corner.

Create Variable

The following variables will be created in this scenario:

Variable NameTypeUsage
jwtAccessTokenBodyReads the $.access_token value from the token response body
jwtExpiresInBody(Optional) Reads the $.expires_in value from the token response body
backendAuthTokenCustom VariableUsed to carry the token value across the policy chain

For the jwtAccessToken variable, select Body as the Type and enter the following value in the JSON Path field:

$.access_token

For the jwtExpiresIn variable, again select the Body type and enter the following value in the JSON Path field:

$.expires_in

For backendAuthToken, select the Custom Variable type. This variable is used when writing the token read from the API Call response to the Authorization header in the After Call stage.

After the related variable definitions are completed, the variables list appears as shown below.

Created Variables
bilgi

For detailed information about variables and their types, see the Variables page.

3) Adding the API Call Policy

The API Call policy can now be added.

Go to the page where API Proxies are listed and select the Swagger Petstore proxy created in the previous steps.

API Proxy Selection

Then go to the Develop tab and click the Add Policy button on the All row in the request pipeline.

Open Policy Selection Popup

On the opened page, select the API Call (REST API Call) policy.

API Call Policy Selection

3.1) Basic Call Settings

The fields on this screen can be examined one by one as follows:

  • Set Call Type to Two-Way-Call (Process Response). Because the token returned in the response after the request must be obtained and processed, not only the outgoing request but also the returned response is important.
  • Set HTTP Method to POST.
  • Enter the token endpoint address in the Base URL field. The sample address in this scenario is:
https://auth.example.com/oauth/token
API Call Basic Settings

3.2) Request — Preparing the Token Request

The request going to the token endpoint can be made by forwarding the original body coming from the client, or by clearing the request body coming from the client and creating a request body for the API Call within the API Call policy.

  • Enable Clear Body Before Call. (To define a custom request body for the API to be called instead of the request body coming from the client.)
  • Enable Use Message Template.
  • Select the type of request body expected by the API in the request body: XML, JSON, x-www-form-urlencoded
  • Enter the fields required to obtain a token in the body content.
In our example, the token service expects the request body as x-www-form-urlencoded, so x-www-form-urlencoded will be used in the example.
KeyValue
grant_typeclient_credentials
client_id<CLIENT_ID>
client_secret<CLIENT_SECRET>
scopeapi.read
API Call Request Settings
uyarı

Instead of keeping sensitive information such as client_id and client_secret as plain text inside the policy, it is recommended to use a Variable / environment variable. In production environments, resolving credentials via a vault or encrypted variable is preferred.

bilgi

Additionally, with a different script to be written, the parameters used during token acquisition can be made dynamic based on the values sent by the user. In this way, the token acquisition process can be customized per user, so that each user obtains a token that belongs to them and matches their own data.

HEADER tab:

  • If the token service expects a Content-Type, add the relevant header.
  • If not needed, Remove All Headers Before Call can be enabled so that unnecessary headers from the client do not go to the token service; then only the required headers are added via New Headers.

Sample new headers:

NameValue
Content-Typeapplication/x-www-form-urlencoded
Acceptapplication/json

3.3) Cache — Caching the JWT

The CACHE tab is configured so that the token service is not called on every request.

Settings to be used in this scenario:

FieldValueDescription
Enable CacheOnCache the token response
Apply By (Cache By)A fixed variable or fixed keyFor a client_credentials scenario, a fixed key is enough for the single token used by the gateway. Example: backend-jwt-token
Capacity100A low capacity is enough since only one/few keys will be stored in this scenario
Cache Storage TypeDISTRIBUTEDDistributed cache is preferred so that all Workers share the same token in a cluster
Cache Null ResponsesOffDo not cache empty/failed token responses
bilgi

With the Apply By feature, separate caching can be performed based on the value of the selected variable. In this way, when the value of the related variable differs in incoming requests, the system does not use the data in the cache; instead it uses the up-to-date data returned from the backend and creates a new cache entry. Thus each request is cached uniquely according to the value it belongs to, and requests can be distinguished from one another.

bilgi

If there is no need for a token-based distinction and Apinizer is the sole authorized user of the related backend, it is recommended to set the cache capacity to 1.

API Call Cache Basic Settings

** By default, cache configuration within API Call is quite simple, as seen in the screenshot above. However, in some cases we may want to cache our token with dynamic TTL instead of a fixed TTL.

For this, the Enable Dynamic TTL option provided within the API Call policy must be enabled.

Dynamic TTL based on JWT lifetime

API Call Cache Settings
bilgi

Instead of a fixed TTL, it is recommended to keep the cache according to the token's real validity period.

There are two common methods for Dynamic TTL configuration:

Method A — JWT exp claim (recommended):

  1. Enable Dynamic TTL.
  2. Select the variable that reads the access_token field from the token response as TTL Source Variable (jwtAccessToken / $.access_token).
  3. Check Value Is Inside JWT Token.
  4. Enter exp in the JWT Claim Name field.
  5. Use Unix Epoch (seconds) as the Value Format (exp is a Unix epoch in seconds).
  6. Enter 30 in the Offset field (expire the cache 30 seconds before the token ends).
  7. Enter 300 in the Fallback TTL field (5 minutes if TTL cannot be parsed).
Dynamic TTL JWT exp Settings

Method B — expires_in field:

If the token response is as follows:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
  1. Enable Dynamic TTL.
  2. Select jwtExpiresIn ($.expires_in) as TTL Source Variable.
  3. Select Expires In (seconds) as Value Format.
  4. Again set Offset to 30 seconds.
bilgi

For a detailed explanation of Dynamic TTL fields, see API Call — Dynamic TTL.

3.4) Response — Adding the Token to the Authorization Header

After the token is obtained (or read from cache), the JWT must be written onto the original request that will go to the backend.

BODY tab:

  • Set Message Template Operation Type to NOT_CHANGE_BODY. This way the body returned from the token service does not overwrite the original request body coming from the client.

Original Message Data Manipulation / HEADER tab:

bilgi

We can add the JWT returned from the API call to the Authorization header using the Original Data Manipulation method. However, in the scenario we are covering, our backend service expects the JWT token with a "Bearer" prefix. To use Apinizer's ability to add a prefix, we must set the JWT from the Header tab, not from the Body tab.

  • Add a new header to the request going to the backend:
NameSourcePrefixDescription
AuthorizationjwtAccessToken variableBEARERAdds a header in Bearer <access_token> format

Steps to set the JWT on the header;

  • Under Response, click New Header inside the Header tab.
After Call Authorization Header
  • On the opened page, select the name of the header where the JWT will be set, the prefix to be added in front of the JWT, and the jwtAccessToken variable from which the JWT value will be taken, then click save to complete setting the JWT on the header.
JWT Header Settings
uyarı

If the request coming from the client already has an Authorization header and only the JWT obtained by the gateway should go to the backend, delete the old Authorization header before After Call, or prevent client credentials from leaking to the backend with an approach similar to Clear Authentication Information.

To complete the operations related to obtaining the token via API Call, configuring the cache, and setting the returned response on the header, click the save button to save the API Call policy.

Save API Call Policy

3.5) Error Message Customization (Optional)

The Error Message Customization tab can be used so that a meaningful error is returned to the client if the token service is unreachable or times out.

Example:

{
"statusCode": 502,
"errorCode": "BACKEND_TOKEN_UNAVAILABLE",
"message": "The backend token service is not responding. Please try again later."
}

After the settings to be used in this scenario are completed, click the Save button in the top right corner.

For the change to take effect, the proxy must be Deployed again.

4) Testing the API Proxy

Select the proxy named Swagger Petstore.

Select an endpoint under the Develop tab. In this scenario the /user/login endpoint will be used.

Click Test Endpoint to test this endpoint.

Click the Send button to send the request directly.

4.1) First request (Cache miss)

On the first request the cache is empty, so the flow proceeds as follows:

  1. API Call sends a POST to the token endpoint.
  2. The returned JWT is written to cache (with Dynamic TTL).
  3. The JWT is added to the Authorization header.
  4. The Backend API is called.

A successful response is received.

First Succeeded Request
bilgi

Because the token service is called on the first request, latency may be higher than on subsequent requests. If Trace / step-by-step monitoring is enabled, the duration of the API Call step can be observed.

4.2) Subsequent requests (Cache hit)

When another request is sent to the same proxy within a short time:

  1. A valid JWT is found in cache.
  2. The token endpoint is not called.
  3. The JWT from cache is written to the Authorization header.
  4. The Backend API is called.
bilgi

To better observe step by step that the JWT, which is the subject of the scenario, is obtained via API Call and cached, we will examine the request that we expect to return from the cache via trace.

To monitor the request via Trace;

  • Go to the Tracing tab and click the Start button on the opened screen.
Tracing Start
  • Return to the Develop tab, select the related endpoint, click the test endpoint button, and send a request with the send button on the opened screen.
Test Endpoint
  • After the request is sent, go back to the Tracing tab and open the detail of the request we sent to observe the details of the flow that took place.
View Detail Trace
  • On the opened screen, select the API Call policy.
Select API Call Policy
  • In the detail of the API Call policy, the Cache:HIT value and that the JWT was successfully set on the header are seen.
View Trace Detail API Call Policy For Caching
bilgi

4.3) When the token expires

Thanks to Dynamic TTL + offset, the cache entry becomes invalid offset seconds before the JWT exp value. On the next request a cache miss occurs again; a new token is obtained and the cache is refreshed. This prevents requests from going to the backend with an expired token.

5) Expected Result and Checklist

When the scenario is configured correctly:

  • Every request going to the backend contains a valid Authorization: Bearer <jwt> header.
  • Unnecessary calls are not made to the token service during the token TTL.
  • When DISTRIBUTED cache is used in a cluster, all Worker instances share the same token.
  • If the token cannot be obtained, the customized error message is returned to the client; the request does not go to the backend without credentials.

Checklist:

  • API Call is defined as SYNCHRONOUS with the correct token URL
  • Body is cleared in Before Call and the token request template is written
  • Cache is on; Dynamic TTL is set with JWT exp or expires_in
  • Offset is defined (e.g. 30 sec)
  • Original body is preserved in After Call (NOT_CHANGE_BODY)
  • Bearer token is added to the Authorization header
  • Proxy is deployed
  • First request and an immediate second request are tested
ipucu

If you need to use the same token across multiple API Proxies, you can define the API Call policy as a Global Policy and attach it to the relevant proxies. For the full list of policy fields, see the API Call documentation.