0

In my React JS (Vite + TS) app Used solution in https://stackoverflow.com/a/53256982/22404569 I am using it for refreshing tokens, BE sends httpOnly cookies as access_tokes so need for the FE to handle tokens.

Problem: I want to redirect user to /login when '/tokens-renew' API fails

My approach I tried to do this using handelLogout(). This approach cannot be done because hooks can only be called inside of a functional component.

I believe handelLogout() is crucial as it manages all the flags that helps in keeping private route

Please note refreshing of tokens and retries of API is working perfectly fine, gets stuck in case of 401 for /tokens-renew and i want to redirect user.

export const handleLogout = () => {
    const dispatch = useDispatch();
    const showToast = useToast();
    const navigate = useNavigate();
    // Clear the local storage and dispatch the signOut action to update the Login flag to false
    localStorage.clear();
    dispatch(signOut()); // Dispatch the action to sign out the user (e.g., clear authentication state in Redux)
    navigate("/login"); // Navigate to the login page 
    showToast("Session expired.", EToastTypes.WARNING); //A custom Hook for Toast msg
};
let isTokenRenewing = false;

...

axios.interceptors.response.use(
    res => res,
    async (err) => {
        // In case of token expire 
        if (err.response.status === 401 && !isTokenRenewing)//Cheks if any API has 401 and there was no req made prior to this 
        {
            isTokenRenewing = true;
            let url = import.meta.env.VITE_API_BASEURL + '/tokens-renew';
            try {
                const response = await axios.get(url);
                if (response.status === 200) {
                    return axios(err.config)
                }
            }
            catch (err) {
                // For case request /tokens-renew got 401 
                // handleLogout()
            }
        }
        // For case request was already made and got 401 
        else {
            // handleLogout()
        }

        return Promise.reject(err);
    }
);
Rohit
  • 1

1 Answers1

0

Have you considered handling that 401 outside the axios interceptor?

I'm thinking you could use a custom hook (https://react.dev/learn/reusing-logic-with-custom-hooks) where you call "/tokens-renew", and handle that response.

It'd look something like this:

export function useIsLoggedIn() {
  const dispatch = useDispatch();
  const showToast = useToast();
  const navigate = useNavigate();
  const apiResponse = service.callAPI(); // Here you'd call tokens-renew

  if(apiRespose.response.status === 401) {
    localStorage.clear();
    dispatch(signOut()); 
    navigate("/login"); 
    showToast("Session expired.", EToastTypes.WARNING);
  }
}

And then you can use that hook wherever you need it, you can alse wrap the API call with a useEffect hook if you want to call that API periodically.