|
- import axios, { AxiosError, InternalAxiosRequestConfig } from "axios";
- import {
- LOGIN_SESSION_EXPIRED_HREF,
- readStoredRefreshToken,
- refreshBackendAccessToken,
- } from "@/app/utils/authToken";
-
- const axiosInstance = axios.create({
- baseURL: process.env.API_URL || process.env.NEXT_PUBLIC_API_URL,
- });
-
- type RetriableConfig = InternalAxiosRequestConfig & { _retry?: boolean };
-
- let requestInterceptorId: number | null = null;
- let responseInterceptorId: number | null = null;
-
- const clearInterceptors = () => {
- if (requestInterceptorId !== null) {
- axiosInstance.interceptors.request.eject(requestInterceptorId);
- requestInterceptorId = null;
- }
- if (responseInterceptorId !== null) {
- axiosInstance.interceptors.response.eject(responseInterceptorId);
- responseInterceptorId = null;
- }
- };
-
- /**
- * Always prefer localStorage accessToken (may have been refreshed) over any
- * closed-over token passed into SetupAxiosInterceptors.
- */
- export const SetupAxiosInterceptors = (_inputToken: string | null) => {
- clearInterceptors();
-
- requestInterceptorId = axiosInstance.interceptors.request.use(
- (config) => {
- try {
- const token =
- (typeof window !== "undefined"
- ? localStorage.getItem("accessToken")
- : null) ?? _inputToken;
- if (token) {
- config.headers.Authorization = `Bearer ${token}`;
- }
- } catch {
- if (_inputToken) {
- config.headers.Authorization = `Bearer ${_inputToken}`;
- }
- }
- return config;
- },
- (error) => Promise.reject(error),
- );
-
- responseInterceptorId = axiosInstance.interceptors.response.use(
- (response) => response,
- async (error: AxiosError) => {
- const status = error.response?.status;
- const original = error.config as RetriableConfig | undefined;
-
- // Only 401 = unauthenticated. Do not treat 403 (forbidden) as session expiry.
- if (status === 401 && original && !original._retry && typeof window !== "undefined") {
- original._retry = true;
- const refreshed = await refreshBackendAccessToken(readStoredRefreshToken());
- if (refreshed) {
- original.headers = original.headers ?? {};
- original.headers.Authorization = `Bearer ${refreshed}`;
- axiosInstance.defaults.headers.Authorization = `Bearer ${refreshed}`;
- return axiosInstance(original);
- }
- window.location.href = LOGIN_SESSION_EXPIRED_HREF;
- }
-
- console.error("API Error:", error.response?.data || error);
- return Promise.reject(error);
- },
- );
- };
-
- export default axiosInstance;
|