How I use Axios interceptor for refreshing token in a custom React hook
Tags: javascript, axios, hooks, react
Published: 2023-10-07 23:11:35


In the world of web development, it's not uncommon to encounter the need for token-based authentication and authorization when working with APIs. However, managing tokens and handling authentication errors can be quite challenging. In this article, we'll walk through the process of creating a custom React hook using Axios to intercept API calls and seamlessly refresh tokens when a 403 error occurs.

### Prerequisites
Before we dive into the code, make sure you have a basic understanding of React, Axios, and state management (e.g., Redux or Context API). In my case, I used Zustand.
 
### Setting Up Axios Instances
The first step is to set up Axios instances. These instances define the base URLs and content type headers for requests. Here's a snippet of how to do it:

```javascript
import axios from 'axios';

export const axBackendInstance = axios.create({
  baseURL: BACKEND_API_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});
```

### Creating the Custom Hook
Now, let's dive into the creation of our custom hook, useAxiosInterceptor, which will handle Axios interceptors for API requests and manage token refreshing.

```javascript
import { AxiosRequestHeaders } from 'axios';
import { axBackendInstance } from './axios-instances'; // Make sure to import your Axios instance
import React from 'react';

const useAxiosInterceptor = () => {
  // Fetch the token refresh function and access token from your application
  const { testToken } = useLogIn(); // You need to implement this
  const accessToken = useAuthStore((state) => state.accessToken);

  // Define request/response and error interceptors
  const reqResInterceptor = (config) => {
    config.headers = {
      Authorization: `Bearer ${accessToken}`,
      // rest of the headers...
    };
    
    return config;
  }

  const reqErrInterceptor = async (error) => Promise.reject(error);

  const resResInterceptor = async (response) => {
    // Handle successful responses as needed
    return response;
  }

  const resErrInterceptor = async (error) => {
    const originalRequest = error.config;
    if (error.response.status === 403 && !originalRequest._retry) {
      originalRequest._retry = true;

      try {
        const newAccessToken = await testToken();
        axBackendInstance.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`;
        // Update the instance header
        return axBackendInstance(originalRequest);
      } catch (error) {
        console.error('Token refresh failed', error);
      }
    }
    return Promise.reject(error);
  }

  // Set up the interceptors with useEffect
  React.useEffect(() => {
    const reqInterceptor = axBackendInstance.interceptors.request.use(
      reqResInterceptor,
      reqErrInterceptor,
    );

    const resInterceptor = axBackendInstance.interceptors.response.use(
      resResInterceptor,
      resErrInterceptor,
    );

    // Cleanup function
    return () => {
      
   axBackendInstance.interceptors.request.eject(reqInterceptor);
     
   axBackendInstance.interceptors.response.eject(resInterceptor);
    }
  }, [accessToken]);

  return { axBe: axBackendInstance };
}
```
The cleanup function is crucial to prevent creating a new interceptor on each render. Without the cleanup function, if a component using the hook unmounts and later remounts, new interceptors will be added. This can result in duplicate interceptors, leading to issues like multiple requests or redundant error handling.

### Using the Custom Hook in Your Components
To use the custom hook in your React components, simply import it and call it within your component. Here's how you can use the useAxiosInterceptor hook:

```javascript
import useAxiosInterceptor from '@/hooks/useAxiosInterceptor';

function MyComponent() {
  const { axBe } = useAxiosInterceptor();

  // Use axBe for making API calls
  axBe.get('/api/some-endpoint')
    .then((response) => {
      // Handle the response here
    })
    .catch((error) => {
      // Handle any errors
    });

  return (
    // Your component JSX
  );
}
```
### Conclusion
Creating a custom React hook for Axios interceptors and token refresh can greatly simplify the management of authentication and API requests in your application. With this approach, you can seamlessly handle token refresh when a 403 error occurs, providing a smooth user experience.

In this post, we've walked you through the process step by step, from setting up Axios instances to creating the custom hook and using it in your components. This can be a powerful addition to your React application, especially in scenarios involving token-based authentication.

Keep in mind that the provided code is a starting point, and you can adapt it to your specific project requirements. Explore additional options for error handling and token management as needed. Happy coding!


###### Great posts that I learned from 
- [React hooks in Axios interceptors](https://dev.to/arianhamdi/react-hooks-in-axios-interceptors-3e1h)
- [Using Axios interceptors for refreshing your API token](https://www.thedutchlab.com/insights/using-axios-interceptors-for-refreshing-your-api-token)