import { authService } from '~/services/auth.service'; /** * Custom fetch composable that handles automatic token refresh * * Flow: * 1. Get token from cookie * 2. Make API request with token * 3. If 401 error (token expired): * - Try to refresh token using refreshToken * - If refresh successful, retry original request * - If refresh fails, redirect to login */ export const useAuthFetch = () => { const config = useRuntimeConfig(); const router = useRouter(); const authFetch = async ( url: string, options: { method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; body?: any; headers?: Record; } = {} ): Promise => { const tokenCookie = useCookie('token'); const refreshTokenCookie = useCookie('refreshToken'); const makeRequest = async (token: string | null) => { return await $fetch(url, { baseURL: config.public.apiBaseUrl as string, method: options.method || 'GET', headers: { ...options.headers, ...(token ? { Authorization: `Bearer ${token}` } : {}) }, body: options.body }); }; try { // Try request with current token return await makeRequest(tokenCookie.value ?? null); } catch (error: any) { // If 401 and we have refresh token, try to refresh if (error.response?.status === 401 && refreshTokenCookie.value) { console.log('Token expired, attempting refresh...'); try { // Refresh token const newTokens = await authService.refreshToken(refreshTokenCookie.value); console.log('Token refreshed successfully'); // Update cookies tokenCookie.value = newTokens.token; refreshTokenCookie.value = newTokens.refreshToken; // Retry original request with new token return await makeRequest(newTokens.token); } catch (refreshError) { console.error('Token refresh failed, redirecting to login'); // Clear cookies tokenCookie.value = null; refreshTokenCookie.value = null; useCookie('user').value = null; // Redirect to login router.push('/login'); throw new Error('Session expired. Please login again.'); } } // Other errors, just throw throw error; } }; return { authFetch }; };