DEV Community

Gagik
Gagik

Posted on

How I use Axios interceptor for refreshing token in a custom React hook

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:

import axios from 'axios';

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

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.

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 };
}
Enter fullscreen mode Exit fullscreen mode

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:

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
  );
}
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)