Archived
- add uv configuration for the backend - update frontend to make auth work - add new auth endpoints - add bookmars feat - add reader feat
67 lines
1.8 KiB
TypeScript
67 lines
1.8 KiB
TypeScript
import axios from "axios";
|
|
|
|
const api = axios.create({
|
|
baseURL: "/api",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
});
|
|
|
|
// Attach JWT token to every request
|
|
api.interceptors.request.use((config) => {
|
|
const token = localStorage.getItem("access_token");
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
return config;
|
|
});
|
|
|
|
// Attempt token refresh on 401
|
|
let isRefreshing = false;
|
|
let pendingRequests: Array<(token: string) => void> = [];
|
|
|
|
api.interceptors.response.use(
|
|
(response) => response,
|
|
async (error) => {
|
|
const originalRequest = error.config;
|
|
if (error.response?.status !== 401 || originalRequest._retry) {
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
if (isRefreshing) {
|
|
return new Promise((resolve) => {
|
|
pendingRequests.push((token: string) => {
|
|
originalRequest.headers.Authorization = `Bearer ${token}`;
|
|
resolve(api(originalRequest));
|
|
});
|
|
});
|
|
}
|
|
|
|
originalRequest._retry = true;
|
|
isRefreshing = true;
|
|
|
|
try {
|
|
const refreshToken = localStorage.getItem("refresh_token");
|
|
if (!refreshToken) {
|
|
throw new Error("No refresh token");
|
|
}
|
|
const { data } = await axios.post("/api/auth/token/refresh/", {
|
|
refresh: refreshToken,
|
|
});
|
|
localStorage.setItem("access_token", data.access);
|
|
pendingRequests.forEach((cb) => cb(data.access));
|
|
pendingRequests = [];
|
|
originalRequest.headers.Authorization = `Bearer ${data.access}`;
|
|
return api(originalRequest);
|
|
} catch {
|
|
localStorage.removeItem("access_token");
|
|
localStorage.removeItem("refresh_token");
|
|
window.location.href = "/auth";
|
|
return Promise.reject(error);
|
|
} finally {
|
|
isRefreshing = false;
|
|
}
|
|
}
|
|
);
|
|
|
|
export default api; |