mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 07:51:02 +00:00
105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
// src/services/api/axiosInstance.ts
|
|
import axios from "axios";
|
|
import Cookies from "js-cookie";
|
|
import { getEnvUrl } from "@/shared/config/env";
|
|
import { getRefreshToken } from "../utils/refreshTokenHandler";
|
|
import {
|
|
getRememberMePreference,
|
|
setAuthCookies,
|
|
} from "../utils/authPersistence";
|
|
import { handleSessionExpiry } from "./sessionExpiry";
|
|
|
|
// Chronicle/audit-log backend is optional in this deployment — no warning
|
|
// when unset; the module's screens are simply non-functional without it.
|
|
const chronicleBaseUrl =
|
|
getEnvUrl("VITE_CHRONICLE_URL", false) ||
|
|
getEnvUrl("VITE_AUDITLOG_API_URL", false);
|
|
|
|
const chronicleInstance = axios.create({
|
|
baseURL: chronicleBaseUrl,
|
|
});
|
|
|
|
// Attach auth token and CSRF defence header to every request
|
|
chronicleInstance.interceptors.request.use((config) => {
|
|
const token = Cookies.get("auth-token");
|
|
if (token) {
|
|
config.headers["Authorization"] = `Bearer ${token}`;
|
|
}
|
|
config.headers["X-Requested-With"] = "XMLHttpRequest";
|
|
return config;
|
|
});
|
|
|
|
let isRefreshing = false;
|
|
let failedQueue: any[] = [];
|
|
|
|
const processQueue = (error: any, token: string | null = null) => {
|
|
failedQueue.forEach((prom) => {
|
|
if (error) prom.reject(error);
|
|
else prom.resolve(token);
|
|
});
|
|
failedQueue = [];
|
|
};
|
|
|
|
const skipRefreshUrls = ["/auth/login", "/auth/refresh", "/auth/me"]; // Add all URLs to skip
|
|
|
|
chronicleInstance.interceptors.response.use(
|
|
(response) => response,
|
|
async (error) => {
|
|
const originalRequest = error.config;
|
|
|
|
// 🔒 Skip refresh logic for specific URLs
|
|
const shouldSkip = skipRefreshUrls.some((url) =>
|
|
originalRequest.url?.includes(url),
|
|
);
|
|
|
|
if (shouldSkip) {
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
if (error.response?.status === 401 && !originalRequest._retry) {
|
|
if (isRefreshing) {
|
|
return new Promise(function (resolve, reject) {
|
|
failedQueue.push({ resolve, reject });
|
|
})
|
|
.then((token) => {
|
|
originalRequest.headers["Authorization"] = "Bearer " + token;
|
|
return chronicleInstance(originalRequest);
|
|
})
|
|
.catch((err) => Promise.reject(err));
|
|
}
|
|
|
|
originalRequest._retry = true;
|
|
isRefreshing = true;
|
|
try {
|
|
const refreshToken = Cookies.get("refresh-token");
|
|
if (!refreshToken) {
|
|
throw new Error("missing-refresh-token");
|
|
}
|
|
const rememberMe = getRememberMePreference();
|
|
|
|
const newToken = await getRefreshToken(refreshToken);
|
|
const updatedToken = newToken.data.token;
|
|
const updatedRefreshToken = newToken.data.refreshToken;
|
|
processQueue(null, newToken.data.token);
|
|
setAuthCookies({
|
|
token: updatedToken,
|
|
refreshToken: updatedRefreshToken,
|
|
rememberMe,
|
|
});
|
|
originalRequest.headers["Authorization"] = `Bearer ${updatedToken}`;
|
|
return chronicleInstance(originalRequest);
|
|
} catch (err) {
|
|
processQueue(err, null);
|
|
handleSessionExpiry();
|
|
return Promise.reject(err);
|
|
} finally {
|
|
isRefreshing = false;
|
|
}
|
|
}
|
|
|
|
return Promise.reject(error);
|
|
},
|
|
);
|
|
|
|
export default chronicleInstance;
|