๐น Axios API Client Setup
import axios from 'axios'
import { API_BASE_URL } from '@/urlconfig.js'
import { useAuthStore } from '@/stores/auth'
-
Creates a reusable
axiosinstance with:baseURLfrom config- JSON
Content-Type - 30-second timeout
const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: { 'Content-Type': 'application/json' },
timeout: 30000,
})
๐น Request Interceptor
apiClient.interceptors.request.use(config => {
const authStore = useAuthStore()
if (authStore.token) config.headers.Authorization = `Bearer ${authStore.token}`
return config
})
- Attaches Authorization header with Bearer token from Pinia
authStore. - Ensures every request is authenticated automatically.
๐น Response Interceptor (Token Refresh)
Handles expired tokens and retries failed requests safely.
let isRefreshing = false
let failedQueue = []
isRefreshingprevents multiple simultaneous refresh attempts.failedQueuestores requests that arrived while refresh is in progress.
Key Logic
- Skip refresh for auth endpoints:
if (originalRequest.url?.includes('/auth/login') ||
originalRequest.url?.includes('/auth/register') ||
originalRequest.url?.includes('/auth/refresh')) {
return Promise.reject(error)
}
- Avoid infinite loops for login/registration/refresh requests.
- Handle 401 (Unauthorized):
if (error.response?.status === 401 && !originalRequest._retry) {
if (!authStore.refreshToken) {
authStore.clearAuth()
return Promise.reject(error)
}
- Checks if refresh token exists.
- Marks the request as
_retryto avoid multiple retries.
- Queue requests during refresh:
if (isRefreshing) {
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject })
}).then(token => {
originalRequest.headers.Authorization = `Bearer ${token}`
return apiClient(originalRequest)
})
}
- Ensures that multiple simultaneous API calls donโt all trigger separate refresh requests.
- Queued requests retry automatically once refresh succeeds.
- Perform token refresh:
const res = await apiClient.post('/auth/refresh', {
refreshToken: authStore.refreshToken
})
const newAccessToken = res.data.accessToken
authStore.setToken(newAccessToken)
processQueue(null, newAccessToken)
- Calls
/auth/refreshendpoint. - Updates the auth store with the new access token.
- Resolves queued requests with the new token.
- Retry the original request:
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`
return apiClient(originalRequest)
- Automatically retries the failed request using the new token.
- Handle refresh failure:
processQueue(err, null)
authStore.clearAuth()
return Promise.reject(err)
- Logs the user out if refresh fails.
- Clears queued requests with an error.
โ Advantages of This Approach
- Automatic token injection.
- Handles concurrent requests safely with a refresh queue.
- Prevents infinite refresh loops.
- Seamless user experience: requests retry automatically after token refresh.