2

I'm working on a larger web-application, which makes several calls to the server from different places. We are using a token which has a lifetime of 15min. Which means it uses the refreshtoken to generate a new token and a new refreshtoken when it gets expired. We are using an interceptor of axios to see that a token got expired. Based on that we are executing a call to generate a new one.

The issue right now is, that all API calls that are made during the time when we make a request to get a new token, will fail!

So my question I have right now is if it is possible to prevent sending requests before a specific call is completely executed (using axios)?

export const runRefreshToken = (errorCallback: () => void): void => {
Axios.interceptors.response.use(
    (response: AxiosResponse<any>): AxiosResponse<any> => {
        return response;
    }, (error: any): any => {
        const original = error.config;
        const loginVerification = !(original.url as string).startsWith("api/login");

        if (error.response && error.response.status === 401 && error.config && loginVerification && !error.config.__retry) {
            return new Promise((resolve): void => {
                original.__retry = true;
                const response = fetch("api/login/refresh-token", { method: 'POST' })
                    .then((): AxiosPromise<any> => {
                        return Axios(original);
                    })
                    .catch((): void => errorCallback())
                resolve(response);
            });
        } else if (error.config.__retry && original.url !== "api/login/verify-authentication") {
            history.push("/login");
        }

        return Promise.reject(error);
    }
);

}

Thanks in advance

Athii
  • 559
  • 5
  • 19
  • Does this answer your question? [How to avoid sending multiple duplicate AJAX requests in axios](https://stackoverflow.com/questions/55868338/how-to-avoid-sending-multiple-duplicate-ajax-requests-in-axios) – Heretic Monkey Aug 23 '21 at 20:27

1 Answers1

0

This is something I have run into on several teams. The solution we have used is a component at the top level of the app that makes the initial request and does not render any of the children until it has succeeded.

import React from 'react';
import { useAuthUser } from './hooks';

export const AuthenticateUser = ({ children }) => {
  const { hasError, isLoading, shouldRedirectToLoginPage, handleRedirectToLoginPage } = useAuthUser();

  if (isLoading) {
    return <LoadingPage>;
  }
  if (hasError) {
    return <ErrorPage>;
  }

  return children;
};

The hook file looks like

import { userSlice } from 'state/user';
import { useAppDispatch } from 'state/hooks';
import { useEffect } from 'react';
import { useUserDetails } from 'api/userRequests';

export function useUserDetailsProps(): UserDetailsProps {
  const { data, isLoading, error } = useUserDetails();

  const dispatch = useAppDispatch();
  useEffect(() => {
    if (data != null) {
      dispatch(userSlice.actions.authenticatedUserReceived(data));
    }
  }, [data, dispatch]);

  return {
    hasError: !!error,
    isLoading,
    shouldRedirectToLoginPage: !!error && error.response?.status === 401,
    handleRedirectToLoginPage,
  };
}
Tall Paul
  • 2,398
  • 3
  • 28
  • 34