Spaces:
Running
Running
File size: 1,675 Bytes
29bcc71 a17d02d 8887fa5 4b8da13 a4301b6 29bcc71 04ba4b7 29bcc71 1878f24 29bcc71 a17d02d 29bcc71 04ba4b7 78865a4 04ba4b7 78865a4 04ba4b7 29bcc71 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | import axios from 'axios'
export const AUTH_UNAUTHORIZED_EVENT = 'gateprep:auth-unauthorized'
const rawApiUrl = import.meta.env.VITE_API_URL || 'http://127.0.0.1:8000'
const BASE_URL = import.meta.env.PROD
? '/api'
: rawApiUrl.split(',')[0].trim()
const api = axios.create({
baseURL: BASE_URL,
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
timeout: 30000,
withCredentials: true,
})
api.interceptors.response.use(
r => r,
err => {
if (err.response?.status === 401) {
const isAuthRoute = err.config?.url?.includes('/auth/')
if (!isAuthRoute) {
window.dispatchEvent(new CustomEvent(AUTH_UNAUTHORIZED_EVENT))
}
}
return Promise.reject(err)
}
)
// ββ Silent token refresh βββββββββββββββββββββββββββββββββββββββββ
// Refreshes the httpOnly auth cookie before it expires.
// Token lifetime is 3 hours; refresh fires every 2.5 hours.
const REFRESH_INTERVAL_MS = 2.5 * 60 * 60 * 1000 // 2.5 hours
let refreshTimer = null
export function startTokenRefresh({ refreshNow = false } = {}) {
stopTokenRefresh()
if (refreshNow) {
// Reset the clock for existing sessions restored from /auth/me.
api.post('/auth/refresh').catch(() => {})
}
refreshTimer = setInterval(async () => {
try {
await api.post('/auth/refresh')
} catch {
// 401 will be caught by the existing interceptor
}
}, REFRESH_INTERVAL_MS)
}
export function stopTokenRefresh() {
if (refreshTimer) {
clearInterval(refreshTimer)
refreshTimer = null
}
}
export default api
|