Приветствую, дорогой читатель! Хочу поделиться решением наболевшей проблемы — автоматическим обновлением access-токена при истечении его срока действия.

Эталонный сценарий

  1. Пользователь успешно авторизуется, после чего access- и refresh-токены сохраняются в куки.

  2. Время жизни access token заканчивается, нужно запросить новый с использованием refresh.

  3. Перед отправкой запроса, требующего acess-токен, проверяем его наличие. Если его нет, отправляем запрос на получение нового.

Пример такой реализации:

api.interceptors.request.use(
  async (config: AxiosRequestConfig) => {
    let accessToken = getCookie('accessToken');
    
    if (!accessToken) {
      accessToken = await refreshAccessToken();
    }
    
    if (accessToken && config.headers) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    
    return config;
  },
  (error: AxiosError) => {
    return Promise.reject(error);
  }
);

const fetchUser = async () => {
  const response = await api.get('/user');
  return response.data;
}

На первый взгляд всё верно, и такой код действительно работает. Но представьте ситуацию: access-токен устарел, и пользователь переходит на новую страницу, где отправляется несколько запросов, требующих токена. Поскольку токен отсутствует, каждый запрос попытается обновить его, не зная, что другой запрос уже это делает.

Правильный сценарий

Вернёмся к моменту, когда мы проверяем наличие токена:

if (!accessToken) {
    accessToken = await refreshAccessToken();
}

Воспользуемся библиотекой axios-jwt-refresh-token.

  1. Создать флаг, который будет указывать, запрашивается ли сейчас новый access-токен.

  2. Организовать очередь запросов, требующих access-токена. Останавливать их и ждать завершения получения нового токена.

  3. После успешного получения токена достать запросы из очереди и продолжить их выполнение.

Как это реализовать?

Воспользуемся библиотекой axios-jwt-refresh-token. Установим необходимые пакеты:

npm install axios-jwt-refresh-token axios js-cookie

Настроим обработчик для Axios:

import axios from 'axios';
import { createTokenRefreshMiddleware } from 'axios-jwt-refresh-token';

// 1. Создаём экземпляр Axios
const axiosInstance = axios.create();

// 2. Функция для обновления токенов
const requestNewTokens = async () => {
  const response = await axios.post('/auth/refresh');
  // Важно вернуть объект в таком формате
  return {
    accessToken: response.data.access_token,
    // Если refresh-токен не нужен, просто удалите эту строку
    refreshToken: response.data.refresh_token 
  };
};

// 3. Создаём middleware для обработки токенов
const requestAccessMiddleware = createTokenRefreshMiddleware({
  requestTokens: requestNewTokens,
  onRefreshAndAccessExpire: () => {
    // Обработка истёкшей сессии
    window.location.href = '/login';
  },
  accessTokenKey: 'accessToken',
  refreshTokenKey: 'refreshToken',
  cookiesOptions: { secure: true, sameSite: 'strict' }
});

// 4. Подключаем middleware к Axios
axiosInstance.interceptors.request.use(requestAccessMiddleware);

Теперь при использовании этого экземпляра Axios вам не нужно вручную передавать access-токен — всё будет работать автоматически.

Комментарии (2)


  1. Contrabondo
    25.07.2025 16:18

    Также можно и готовые адаптеры использовать, например для keycloak есть его готовый, с апдейтами и прочим:

    https://www.npmjs.com/package/keycloak-js

    А так смысл правильный. Иногда ещё бывает надо добавлять апдейты на активации окон/вкладок, а не только при запросах


    1. artemmorozov13 Автор
      25.07.2025 16:18

      Спасибо за замечание, забыл об этом, добавлю обработку в следующей версии