import { sessionManager } from '~/server/utils/session-manager' export default defineNuxtRouteMiddleware(async (to) => { // Skip auth for SSR if (import.meta.server) return; // Check if auth is required (default true unless explicitly set to false) const isAuthRequired = to.meta.auth !== false; if (!isAuthRequired) { console.log('[MIDDLEWARE] Auth not required for route:', to.path); return; } // Skip auth check if we're already on the login page to prevent redirect loops if (to.path === '/login' || to.path.startsWith('/auth')) { return; } console.log('[MIDDLEWARE] Checking authentication for route:', to.path); // Use session manager for centralized session handling const nuxtApp = useNuxtApp(); const cacheKey = 'auth:session:cache'; const baseExpiry = 3 * 60 * 1000; // 3 minutes base cache const jitter = Math.floor(Math.random() * 10000); // 0-10 seconds jitter const cacheExpiry = baseExpiry + jitter; // Prevent thundering herd try { // Use SessionManager for deduped session checks const sessionData = await sessionManager.checkSession({ nuxtApp, cacheKey, cacheExpiry, fetchFn: async () => { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 10000); // 10 second timeout try { const result = await $fetch('/api/auth/session', { signal: controller.signal, retry: 2, retryDelay: 1000, onRetry: ({ retries }: { retries: number }) => { console.log(`[MIDDLEWARE] Retrying auth check (attempt ${retries + 1})`) }, onResponseError({ response }) { // Clear cache only on actual auth errors, not 404s or other errors if (response.status === 401) { console.log('[MIDDLEWARE] Unauthorized error detected, clearing cache') sessionManager.clearCache(); delete nuxtApp.payload.data?.authState; } else if (response.status === 403) { console.log('[MIDDLEWARE] Forbidden error detected, partial cache clear') // Don't clear cache on 403 as user is authenticated but lacks permissions } // Ignore 404s and other errors - they're not authentication issues } }) as any; clearTimeout(timeout); return result; } catch (error) { clearTimeout(timeout); throw error; } } }); // Store auth state for components if (!nuxtApp.payload.data) { nuxtApp.payload.data = {}; } nuxtApp.payload.data.authState = { user: sessionData.user, authenticated: sessionData.authenticated, groups: sessionData.groups || [] }; console.log('[MIDDLEWARE] Session check result:', { authenticated: sessionData.authenticated, hasUser: !!sessionData.user, userId: sessionData.user?.id, groups: sessionData.groups || [], fromCache: sessionData.fromCache, reason: sessionData.reason }); if (sessionData.authenticated && sessionData.user) { console.log('[MIDDLEWARE] User authenticated, allowing access'); // Check for any auth errors from authorization middleware if (nuxtApp.payload.authError) { const toast = useToast(); toast.error(String(nuxtApp.payload.authError)); delete nuxtApp.payload.authError; } return; } console.log('[MIDDLEWARE] No valid authentication found, redirecting to login'); return navigateTo('/login'); } catch (error: any) { console.error('[MIDDLEWARE] Auth check failed:', error); // Show warning for cached results due to network errors if (error.reason === 'NETWORK_ERROR_CACHED') { const toast = useToast(); toast.warning('Network connectivity issue - using cached authentication'); } return navigateTo('/login'); } });