skip to Main Content

I am using Axios interceptor to get new Access token with refresh token. The following code creates new access token from server, but I cannot find the cookie in the browser.

Works fine, but the browser struck on loading.

It could be much helpful, if someone can find where the issue is.

Advance thanks.


interface RetryQueueItem {
  resolve: (value?: any) => void;
  reject: (error?: any) => void;
  config: AxiosRequestConfig;
}

const fetchAxiosClient: AxiosInstance = axios.create({
  baseURL: 'http://localhost:8080/api/v1',
  timeout: 60000
});
fetchAxiosClient.defaults.headers.common = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
} as headers;

export async function createAxiosInstance(requestEvent) {

  // Auth token to request header
  fetchAxiosClient.interceptors.request.use(
    (config: InternalAxiosRequestConfig) => {
      const token = getAccessToken(requestEvent.cookieObj).access_token;
      if (token) {
        config.headers['Authorization'] = `Bearer ${token}`;
      }
      config.headers['Content-Type'] = 'application/json';
      return config;
    },
    error => Promise.reject(error)
  );

  const refreshAndRetryQueue: RetryQueueItem[] = [];
  let isRefreshing = false;

  fetchAxiosClient.interceptors.response.use(
    function (response: AxiosResponse) {
      return response;
    },
    async function (error: any) {
      const originalRequest: AxiosRequestConfig = error.config;
      if (error.response && error.response.status === 401) {
        if (!isRefreshing) {
          isRefreshing = true;
          try {
            const refreshToken = getRefreshToken(requestEvent.cookieObj);
            if (refreshToken) {
              await axios.post(
                `${fetchAxiosClient?.defaults.baseURL}${REFRESH_TOKEN}`,
                {
                  refresh_token: refreshToken,
                }
              ).then(async (response: any) => {
                const cookies = response.headers['set-cookie'] as string[];
                const accessToken = getToken(cookies[0], APP_CONSTANTS.ACCESS_TOKEN);
                setToken(requestEvent.cookieObj, accessToken!);
                return fetchAxiosClient!(originalRequest);
              }).catch((error) => {
                requestEvent.cookieObj.delete(APP_CONSTANTS.ACCESS_TOKEN, { path: '/' });
                throw requestEvent.redirect(302, '/login');
                //return Promise.reject(error);
              });
              refreshAndRetryQueue.forEach(({ config, resolve, reject }) => {
                fetchAxiosClient!(config)
                  .then((response) => resolve(response))
                  .catch((err) => reject(err));
              });
              refreshAndRetryQueue.length = 0;
            } else {
                requestEvent.cookieObj.delete(APP_CONSTANTS.ACCESS_TOKEN, { path: '/' });
              window.location.href = "/";
              return Promise.reject(error);
            }
          } catch (refreshError) {
            refreshAndRetryQueue.length = 0;
            requestEvent.cookieObj.delete(APP_CONSTANTS.ACCESS_TOKEN, { path: '/' });
          } finally {
            isRefreshing = false;
          }
        }
        return new Promise<void>((resolve, reject) => {
          refreshAndRetryQueue.push({ config: originalRequest, resolve, reject });
        });
      }
      return Promise.reject(error);
    }
  );
}

The new generated access token which will expire in 15 mins should set as cookie. The moment access token expired, new access token should be generated with refresh token.

But, after expiry of access token, while generating new access token the browser shows loading indicator and continuously busy.

2

Answers


  1. Chosen as BEST ANSWER

    I referred this

    https://blog.stackademic.com/refresh-access-token-with-axios-interceptors-in-react-js-with-typescript-bd7a2d035562

    working fine.

    export async function createAxiosInstance(cookieObj: Cookie) {
        interface FailedRequests {
          resolve: (value: AxiosResponse) => void;
          reject: (value: AxiosError) => void;
          config: AxiosRequestConfig;
          error: AxiosError;
        }
        // Add the auth token to every request
        fetchAxiosClient.interceptors.request.use(
          (config: InternalAxiosRequestConfig) => {
            const token = getAccessToken(cookieObj).access_token;
            if (token) {
              config.headers['Authorization'] = `Bearer ${token}`;
            }
            config.headers['Content-Type'] = 'application/json';
            return config;
          },
          error => Promise.reject(error)
        );
      
        let failedRequests: FailedRequests[] = [];
        let isTokenRefreshing = false;
      
        fetchAxiosClient.interceptors.response.use(
          function (response: AxiosResponse) {
            return response;
          },
          async (error: AxiosError) => {
            const status = error.response?.status;
            const originalRequestConfig = error.config!;
      
            if (status !== 401) {
              return Promise.reject(error);
            }
      
            if (isTokenRefreshing) {
              return new Promise((resolve, reject) => {
                failedRequests.push({
                  resolve,
                  reject,
                  config: originalRequestConfig,
                  error: error,
                });
              });
            }
      
            isTokenRefreshing = true;
            const refreshToken = getRefreshToken(cookieObj);
            try {
              const response = await fetchAxiosClient.post(
                `${fetchAxiosClient?.defaults.baseURL}${REFRESH_TOKEN}`,
                      {
                        refresh_token: refreshToken,
                      }
              );
              const cookies = response.headers['set-cookie'] as string[];
              const accessToken = getToken(cookies[0], APP_CONSTANTS.ACCESS_TOKEN);
              setToken(cookieObj, accessToken!);
              failedRequests.forEach(({ resolve, reject, config }) => {
                fetchAxiosClient(config)
                  .then((response) => resolve(response))
                  .catch((error) => reject(error));
              });
            } catch (_error: unknown) {
              console.error(_error);
              failedRequests.forEach(({ reject, error }) => reject(error));
              cookieObj.delete(APP_CONSTANTS.ACCESS_TOKEN, { path: '/' });
              return Promise.reject(error);
            } finally {
              failedRequests = [];
              isTokenRefreshing = false;
            }
            return fetchAxiosClient(originalRequestConfig);
          }
        );
      }
    

  2. The code logic looks messy. Use this plugin to make your code easier:

    https://github.com/Flyrell/axios-auth-refresh

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search