import axios, { type AxiosError, type InternalAxiosRequestConfig } from 'axios'; import { AUTH_SCOPE } from '@/constants/auth'; import { env } from '@/config/env'; import { getAccessToken, getRefreshToken, storeAuthTokens, clearAuthTokens } from '@/utils/authToken'; import { logout } from '@/utils/logout'; import { buildAuthUrl } from '@/utils/authUrl'; import { createBasicAuthHeader } from '@/config/env'; import type { TokenResponse } from '@/types/auth'; const apiBaseUrl = env.apiBaseUrl; const api = axios.create({ baseURL: apiBaseUrl, timeout: 10000, headers: { 'Content-Type': 'application/json', }, }); let refreshPromise: Promise | null = null; api.interceptors.request.use((config) => { const token = getAccessToken(); if (token && config.headers) { config.headers.Authorization = `Bearer ${token}`; } return config; }); api.interceptors.response.use( (response) => response, async (error: AxiosError) => { const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean }; if (!error.response || error.response.status !== 401 || originalRequest._retry) { return Promise.reject(error); } if (!refreshPromise) { refreshPromise = (async () => { const refreshToken = getRefreshToken(); if (!refreshToken) { throw new Error('Missing refresh token'); } const params = new URLSearchParams(); params.append('grant_type', 'refresh_token'); params.append('refresh_token', refreshToken); params.append('scope', AUTH_SCOPE); const response = await axios.post(buildAuthUrl('/accounts/oauth2/token/'), params, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', Authorization: createBasicAuthHeader(), }, }); storeAuthTokens({ access_token: response.data.access_token, refresh_token: response.data.refresh_token, }); })().catch(() => { clearAuthTokens(); logout(); return undefined; }); } try { await refreshPromise; originalRequest._retry = true; const token = getAccessToken(); if (token && originalRequest.headers) { originalRequest.headers.Authorization = `Bearer ${token}`; } return api(originalRequest); } finally { refreshPromise = null; } }, ); export default api;