Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically refreshing access token by AXIOS interceptor request

My React App uses Axios for API-requests.

Axios adds access token into headers every API-request by request interceptor. I want check expiry date before current request will be sent. If access token expired, axios should make refresh action, change access token in store and then make first request from app with new token.

For refreshing and other API-actions I use Redux Toolkit Slices.

I have no any cases when refreshing in request interceptor works fine. I found solutions with response interceptor, but it's not my way.

How can I refresh access token in request interceptor?

This is my axios instance:

export const createAPI = (): AxiosInstance => {
  const api = axios.create({
    baseURL: getAPIURL(),
    timeout: REQUEST_TIMEOUT,
    withCredentials: true
  });

  api.interceptors.request.use(
    async (config: InternalAxiosRequestConfig) => {
      const accessToken = store.getState().user.accessToken;

      if (accessToken && config.headers) {
        config.headers['authorization'] = `Bearer ${accessToken}`;
      }
      
      // todo Check access token and refresh if it expired

      if (!config.data) return config;
      
      config.data = adaptFromClientToServer(config.data);

      return config;
    }
  );

  api.interceptors.response.use(
    (response) => {
      if (!response.data) return response;
      
      response.data = adaptFromServerToClient(response.data);
      
      return response;
    }
  );

  return api;
};
like image 231
Eujenio Gonzalez Avatar asked Sep 04 '26 14:09

Eujenio Gonzalez


2 Answers

Your createApi module looks on the right tracks, to wrap common API logic (which gets more complex over time) and simplify code in views and view models. My answer is about design choices for portable and resilient API clients.

TOKEN RESPONSES

A token response always contains an expires_in field. Note also that the access token may be an opaque / unreadable token rather than a JWT:

{
   "token_type":"bearer",
   "access_token":"_0XBPWQQ_c0f0677f-5aa9-4c4e-a3d4-c0f53db4037a",
   "refresh_token":"_1XBPWQQ_197003c2-704f-4475-923c-2b40e5f5d696",
   "scope":"openid profile",
   "expires_in":900
}

REFRESH CHOICES

The frontend can hold onto the expires_in field and the time of issuance, and manage refresh via one of these methods:

  1. Do a refresh before API requests if the current time indicates the token is close to expiry

  2. Do a refresh on a background timer when the token is close to expiry

  3. Do a refresh if an API returns a 401 status

RESILIENCY

Access tokens can fail for reasons other than expiry. One cause can be revocation. In some setups it can be caused by infrastructure events such as token signing key renewal or a load balancing failover. Therefore always do option 3 (the primary behaviour), and combine it with option 1 or 2 (optimizations) depending on your preference.

CONCURRENCY

Token refresh should be synchronized if multiple views call APIs at the same time. This leads to a design of queueing up promises, but only making the refresh request on the first, then resuming all API requests with the new access token. Code like this could be used:

public async synchronizedRefresh(): Promise<void> {
    await this._concurrencyHandler.execute(this._performTokenRefresh);
}

FURTHER INFO

My API client journey blog post has some further info on this area of coding resilient OAuth clients.

like image 82
Gary Archer Avatar answered Sep 06 '26 18:09

Gary Archer


When checking whether a token has expired in the request interceptor, it's important to note that if the token is not expired on the frontend, it doesn't necessarily mean it's still valid on the backend. There may be a time lag between the frontend and backend systems. To ensure token validity, it's advisable to implement solutions on both the request interceptor and response interceptor.

Moreover, in scenarios where the API URL is public, there's no need to initiate a token refresh if a token isn't required. In such cases, it's efficient to skip the refresh token API call. This approach helps optimize token management by avoiding unnecessary refresh operations when tokens are not in use.

Relying solely on the request interceptor to check the refresh token is not a recommended approach.

like image 40
stevex Avatar answered Sep 06 '26 18:09

stevex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!