EduPlatform / frontend /src /api /client.js
erranova's picture
Upload 720 files
8fd091f verified
Raw History Blame Contribute Delete
2.22 kB
import axios from 'axios'
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL || '/api',
timeout: 15000,
headers: { 'Content-Type': 'application/json' },
withCredentials: true,
})
// ─── Request interceptor: attach JWT ─────────────────────────────────────────
api.interceptors.request.use(config => {
const token = localStorage.getItem('access_token')
if (token) config.headers.Authorization = `Bearer ${token}`
return config
}, error => Promise.reject(error))
// ─── Response interceptor: auto-refresh token ────────────────────────────────
let isRefreshing = false
let failedQueue = []
const processQueue = (error, token = null) => {
failedQueue.forEach(prom => error ? prom.reject(error) : prom.resolve(token))
failedQueue = []
}
api.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config
if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject })
}).then(token => {
originalRequest.headers.Authorization = `Bearer ${token}`
return api(originalRequest)
})
}
originalRequest._retry = true
isRefreshing = true
try {
const refresh = localStorage.getItem('refresh_token')
if (!refresh) throw new Error('No refresh token')
const { data } = await axios.post('/api/auth/token/refresh/', { refresh })
localStorage.setItem('access_token', data.access)
processQueue(null, data.access)
originalRequest.headers.Authorization = `Bearer ${data.access}`
return api(originalRequest)
} catch (err) {
processQueue(err, null)
localStorage.removeItem('access_token')
localStorage.removeItem('refresh_token')
window.location.href = '/login'
return Promise.reject(err)
} finally {
isRefreshing = false
}
}
return Promise.reject(error)
}
)
export default api