mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 03:10:54 +00:00
131 lines
3.5 KiB
TypeScript
131 lines
3.5 KiB
TypeScript
import {
|
|
UseQueryOptions,
|
|
QueryObserverOptions,
|
|
} from "@tanstack/react-query";
|
|
import axios, { AxiosError, InternalAxiosRequestConfig } from "axios";
|
|
import { URL_CONSTANTS } from "@/constants/URLS";
|
|
|
|
const client = axios.create({
|
|
baseURL: import.meta.env.VITE_API_URL,
|
|
});
|
|
|
|
function getCookie(name: string): string | undefined {
|
|
return document.cookie
|
|
.split("; ")
|
|
.find((row) => row.startsWith(`${name}=`))
|
|
?.split("=")[1];
|
|
}
|
|
|
|
function setCookie(name: string, value: string, days: number) {
|
|
const expires = new Date();
|
|
expires.setDate(expires.getDate() + days);
|
|
document.cookie = `${name}=${value}; path=/; expires=${expires.toUTCString()}; SameSite=Lax`;
|
|
}
|
|
|
|
function clearAuthCookies() {
|
|
["auth-token", "refresh-token", "auth-user", "current-position-id", "selected-position-id"].forEach(
|
|
(name) => {
|
|
document.cookie = `${name}=; Max-Age=0; path=/`;
|
|
},
|
|
);
|
|
}
|
|
|
|
// Attach auth token to every request
|
|
client.interceptors.request.use((config) => {
|
|
const token = getCookie("auth-token");
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
return config;
|
|
});
|
|
|
|
// Token refresh state
|
|
let isRefreshing = false;
|
|
let failedQueue: {
|
|
resolve: (token: string) => void;
|
|
reject: (error: unknown) => void;
|
|
}[] = [];
|
|
|
|
function processQueue(error: unknown, token?: string) {
|
|
failedQueue.forEach(({ resolve, reject }) => {
|
|
if (error) {
|
|
reject(error);
|
|
} else {
|
|
resolve(token!);
|
|
}
|
|
});
|
|
failedQueue = [];
|
|
}
|
|
|
|
// Handle auth errors globally with token refresh
|
|
client.interceptors.response.use(
|
|
(response) => response,
|
|
async (error: AxiosError) => {
|
|
const originalRequest = error.config as InternalAxiosRequestConfig & {
|
|
_retry?: boolean;
|
|
};
|
|
|
|
// Don't intercept if:
|
|
// - no response (network error)
|
|
// - status is not 401
|
|
// - already retried
|
|
// - it's the refresh endpoint itself
|
|
if (
|
|
!error.response ||
|
|
error.response.status !== 401 ||
|
|
originalRequest._retry ||
|
|
originalRequest.url === URL_CONSTANTS.AUTH.REFRESH_TOKEN
|
|
) {
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
if (isRefreshing) {
|
|
return new Promise<string>((resolve, reject) => {
|
|
failedQueue.push({ resolve, reject });
|
|
}).then((token) => {
|
|
originalRequest.headers.Authorization = `Bearer ${token}`;
|
|
return client(originalRequest);
|
|
});
|
|
}
|
|
|
|
originalRequest._retry = true;
|
|
isRefreshing = true;
|
|
|
|
const refreshToken = getCookie("refresh-token");
|
|
|
|
if (!refreshToken) {
|
|
isRefreshing = false;
|
|
clearAuthCookies();
|
|
if (window.location.pathname !== "/login") {
|
|
window.location.href = "/login";
|
|
}
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
try {
|
|
const { data } = await client.post<{ data: { token: string; refreshToken: string } }>(
|
|
URL_CONSTANTS.AUTH.REFRESH_TOKEN,
|
|
{ refreshToken },
|
|
);
|
|
const { token, refreshToken: newRefreshToken } = data.data;
|
|
setCookie("auth-token", token, 7);
|
|
setCookie("refresh-token", newRefreshToken, 7);
|
|
originalRequest.headers.Authorization = `Bearer ${token}`;
|
|
processQueue(null, token);
|
|
return client(originalRequest);
|
|
} catch (refreshError) {
|
|
processQueue(refreshError, undefined);
|
|
clearAuthCookies();
|
|
if (window.location.pathname !== "/login") {
|
|
window.location.href = "/login";
|
|
}
|
|
return Promise.reject(refreshError);
|
|
} finally {
|
|
isRefreshing = false;
|
|
}
|
|
},
|
|
);
|
|
|
|
export { client };
|
|
export type { UseQueryOptions, QueryObserverOptions };
|