Search code examples
javascriptreactjstypescriptaxiosplaywright

How to refresh token in axios?


My question is related to customAxios.interceptors.response.use . My purpose here is; if the token expired and I got a 401 error, make a request again where I got a 401 error and write the new token to the headers. On the other hand, if I get an error except for the 401 error, show me the error.response.data . Do you think this logic is set up correctly? I tried to test but I wasn't sure especially 401 error cases

import axios from "axios";
import { LoginAPI } from "../playwright/tests/login/login.api";
import { test } from "@playwright/test"
import {configEnv} from "../config/config"

test.beforeAll(async () => {
    await LoginAPI.API.Signin.run()
});
const customAxios = axios.create({
    baseURL: configEnv.apiBaseURL
});

customAxios.interceptors.request.use(
    async (config) => {
        if (config.headers) {
            config.headers['Authorization'] = `Bearer ${LoginAPI.States.token}`;
            return config;
        }
        return config;
    },
    (error) => {
        Promise.reject(error);
    }
);

customAxios.interceptors.response.use(
    function(response) {
      return response;
    },
   async function(error) {
      if (401 === error.response.status) {
        await LoginAPI.API.Signin.run()
        customAxios.defaults.headers.common['Authorization'] = `Bearer ${LoginAPI.States.token}`
      } else {
        return Promise.reject(error.response.data);
      }
    }
  );

export default customAxios

Solution

  • I would recommend you to store your token in a localStorage and then replace it after refresh. This way you can set a token in your API class in one place.

    import axios from "axios";
    
    export const ApiClient = () => {
        // Create a new axios instance
        const api = axios.create({
            baseURL: "URL",
            headers: {
                "Content-Type": "application/json",
                Accept: "application/json",
            },
        });
    
        // Add a request interceptor to add the JWT token to the authorization header
        api.interceptors.request.use(
            (config) => {
                const token = sessionStorage.getItem("jwtToken");
                if (token) {
                    config.headers.Authorization = `Bearer ${token}`;
                }
                return config;
            },
            (error) => Promise.reject(error)
        );
    
        // Add a response interceptor to refresh the JWT token if it's expired
        api.interceptors.response.use(
            (response) => response,
            (error) => {
                const originalRequest = error.config;
    
                // If the error is a 401 and we have a refresh token, refresh the JWT token
                if (
                    error.response.status === 401 &&
                    sessionStorage.getItem("refreshToken")
                ) {
                    const refreshToken = sessionStorage.getItem("refreshToken");
    
                    let data = JSON.stringify({
                        refresh_token: refreshToken,
                    });
    
                    post("/refreshToken", data)
                        .then((response) => {
                            sessionStorage.setItem("jwtToken", response.token);
                            sessionStorage.setItem("refreshToken", response.refresh_token);
    
                            // Re-run the original request that was intercepted
                            originalRequest.headers.Authorization = `Bearer ${response.token}`;
                            api(originalRequest)
                                .then((response) => {
                                    return response.data;
                                })
                                .catch((error) => {
                                    console.log(error);
                                });
                            // return api(originalRequest)
                        })
                        .catch((err) => {
                            // If there is an error refreshing the token, log out the user
                            console.log(err);
                        });
                }
    
                // Return the original error if we can't handle it
                return Promise.reject(error);
            }
        );
    
        const login = (email, password) => {
            return api
                .post("/authentication_token", { email, password })
                .then(({ data }) => {
                    // Store the JWT and refresh tokens in session storage
                    sessionStorage.setItem("jwtToken", data.token);
                    sessionStorage.setItem("refreshToken", data.refresh_token);
                })
                .catch((err) => {
                    // Return the error if the request fails
                    return err;
                });
        };
    
    
        const get = (path) => {
            return api.get(path).then((response) => response.data);
        };
    
        const post = (path, data) => {
            return api.post(path, data).then((response) => response.data);
        };
    
        const put = (path, data) => {
            return api.put(path, data).then((response) => response.data);
        };
    
        const del = (path) => {
            return api.delete(path).then((response) => response);
        };
    
    
    
        return {
            login,
            get,
            post,
            put,
            del,
        };
    };
    
    

    Best, Chris