2025-07-06 11:07:01 -05:00
|
|
|
export default function ({ $axios, store, $root, app }) {
|
2025-06-29 17:22:58 -05:00
|
|
|
// Track if we're currently refreshing to prevent multiple refresh attempts
|
|
|
|
let isRefreshing = false
|
|
|
|
let failedQueue = []
|
|
|
|
|
|
|
|
const processQueue = (error, token = null) => {
|
|
|
|
failedQueue.forEach(({ resolve, reject }) => {
|
|
|
|
if (error) {
|
|
|
|
reject(error)
|
|
|
|
} else {
|
|
|
|
resolve(token)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
failedQueue = []
|
|
|
|
}
|
|
|
|
|
2024-10-16 17:42:00 -05:00
|
|
|
$axios.onRequest((config) => {
|
2021-10-17 18:05:43 -05:00
|
|
|
if (!config.url) {
|
|
|
|
console.error('Axios request invalid config', config)
|
|
|
|
return
|
|
|
|
}
|
2021-08-21 13:02:24 -05:00
|
|
|
if (config.url.startsWith('http:') || config.url.startsWith('https:')) {
|
|
|
|
return
|
|
|
|
}
|
2025-06-29 17:22:58 -05:00
|
|
|
const bearerToken = store.getters['user/getToken']
|
2021-08-17 17:01:11 -05:00
|
|
|
if (bearerToken) {
|
|
|
|
config.headers.common['Authorization'] = `Bearer ${bearerToken}`
|
|
|
|
}
|
2023-06-15 17:41:27 -05:00
|
|
|
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
|
|
console.log('Making request to ' + config.url)
|
|
|
|
}
|
2021-08-17 17:01:11 -05:00
|
|
|
})
|
|
|
|
|
2025-06-29 17:22:58 -05:00
|
|
|
$axios.onError(async (error) => {
|
|
|
|
const originalRequest = error.config
|
2021-08-17 17:01:11 -05:00
|
|
|
const code = parseInt(error.response && error.response.status)
|
2021-09-29 10:16:38 -05:00
|
|
|
const message = error.response ? error.response.data || 'Unknown Error' : 'Unknown Error'
|
2025-06-29 17:22:58 -05:00
|
|
|
|
2021-09-29 10:16:38 -05:00
|
|
|
console.error('Axios error', code, message)
|
2025-06-29 17:22:58 -05:00
|
|
|
|
|
|
|
// Handle 401 Unauthorized (token expired)
|
|
|
|
if (code === 401 && !originalRequest._retry) {
|
|
|
|
// Skip refresh for auth endpoints to prevent infinite loops
|
|
|
|
if (originalRequest.url === '/auth/refresh' || originalRequest.url === '/login') {
|
|
|
|
// Refresh failed or login failed, redirect to login
|
|
|
|
store.commit('user/setUser', null)
|
2025-07-08 09:45:24 -05:00
|
|
|
store.commit('user/setUserToken', null)
|
2025-06-29 17:22:58 -05:00
|
|
|
app.router.push('/login')
|
|
|
|
return Promise.reject(error)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isRefreshing) {
|
|
|
|
// If already refreshing, queue this request
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
failedQueue.push({ resolve, reject })
|
|
|
|
})
|
|
|
|
.then((token) => {
|
|
|
|
if (!originalRequest.headers) {
|
|
|
|
originalRequest.headers = {}
|
|
|
|
}
|
|
|
|
originalRequest.headers['Authorization'] = `Bearer ${token}`
|
|
|
|
return $axios(originalRequest)
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
return Promise.reject(err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
originalRequest._retry = true
|
|
|
|
isRefreshing = true
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Attempt to refresh the token
|
|
|
|
const response = await $axios.$post('/auth/refresh')
|
|
|
|
const newAccessToken = response.user.accessToken
|
|
|
|
|
|
|
|
if (!newAccessToken) {
|
|
|
|
console.error('No new access token received')
|
|
|
|
return Promise.reject(error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the token in store and localStorage
|
|
|
|
store.commit('user/setUser', response.user)
|
2025-07-08 09:45:24 -05:00
|
|
|
store.commit('user/setUserToken', newAccessToken)
|
2025-06-29 17:22:58 -05:00
|
|
|
|
2025-07-06 11:07:01 -05:00
|
|
|
// Emit event used to re-authenticate socket in default.vue since $root is not available here
|
|
|
|
if (app.$eventBus) {
|
|
|
|
app.$eventBus.$emit('token_refreshed', newAccessToken)
|
|
|
|
}
|
|
|
|
|
2025-06-29 17:22:58 -05:00
|
|
|
// Update the original request with new token
|
|
|
|
if (!originalRequest.headers) {
|
|
|
|
originalRequest.headers = {}
|
|
|
|
}
|
|
|
|
originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`
|
|
|
|
|
|
|
|
// Process any queued requests
|
|
|
|
processQueue(null, newAccessToken)
|
|
|
|
|
|
|
|
// Retry the original request
|
|
|
|
return $axios(originalRequest)
|
|
|
|
} catch (refreshError) {
|
|
|
|
console.error('Token refresh failed:', refreshError)
|
|
|
|
|
|
|
|
// Process queued requests with error
|
|
|
|
processQueue(refreshError, null)
|
|
|
|
|
|
|
|
// Clear user data and redirect to login
|
|
|
|
store.commit('user/setUser', null)
|
2025-07-08 09:45:24 -05:00
|
|
|
store.commit('user/setUserToken', null)
|
2025-06-29 17:22:58 -05:00
|
|
|
app.router.push('/login')
|
|
|
|
|
|
|
|
return Promise.reject(refreshError)
|
|
|
|
} finally {
|
|
|
|
isRefreshing = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.reject(error)
|
2021-08-17 17:01:11 -05:00
|
|
|
})
|
2024-10-16 17:42:00 -05:00
|
|
|
}
|