diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index 88dd027d..f659b25f 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -88,13 +88,15 @@ const getAuthToken = (): string | null => { } // Fallback to localStorage (for cases where store hasn't initialized yet) - const authStorage = localStorage.getItem('auth-store'); + // CRITICAL: Use 'auth-storage' to match authStore persist config + const authStorage = localStorage.getItem('auth-storage'); if (authStorage) { const parsed = JSON.parse(authStorage); return parsed?.state?.token || null; } } catch (e) { // Ignore parsing errors + console.warn('Failed to get auth token:', e); } return null; }; @@ -109,13 +111,15 @@ const getRefreshToken = (): string | null => { } // Fallback to localStorage (for cases where store hasn't initialized yet) - const authStorage = localStorage.getItem('auth-store'); + // CRITICAL: Use 'auth-storage' to match authStore persist config + const authStorage = localStorage.getItem('auth-storage'); if (authStorage) { const parsed = JSON.parse(authStorage); return parsed?.state?.refreshToken || null; } } catch (e) { // Ignore parsing errors + console.warn('Failed to get refresh token:', e); } return null; }; @@ -160,16 +164,15 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo const errorData = text ? JSON.parse(text) : null; const errorMessage = errorData?.detail || errorData?.message || errorData?.error || response.statusText; - // Check if it's an authentication credentials error + // Check if it's an authentication credentials error (NOT permission/plan errors) if (errorMessage?.includes?.('Authentication credentials') || - errorMessage?.includes?.('not authenticated') || - errorMessage?.includes?.('Invalid token') || - errorMessage?.includes?.('Token has expired')) { + errorMessage?.includes?.('not authenticated')) { - // CRITICAL: Authentication token is invalid/missing - force logout + // CRITICAL: Only force logout if we're actually authenticated but token is missing/invalid + // Don't logout for permission errors or plan issues const authState = useAuthStore.getState(); if (authState?.isAuthenticated || authState?.token) { - console.warn('Authentication token invalid - forcing logout'); + console.warn('Authentication credentials missing - forcing logout'); const { logout } = useAuthStore.getState(); logout(); @@ -186,7 +189,7 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo throw err; } - // Not an auth error - could be permissions/plan issue + // Not an auth error - could be permissions/plan issue - don't force logout let err: any = new Error(errorMessage); err.status = 403; err.data = errorData; @@ -235,8 +238,13 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo const refreshData = await refreshResponse.json(); const accessToken = refreshData.data?.access || refreshData.access; if (refreshData.success && accessToken) { - // Update token in store + // Update token in Zustand store AND localStorage try { + // Update Zustand store directly + const { setToken } = useAuthStore.getState(); + setToken(accessToken); + + // Also update localStorage for immediate availability const authStorage = localStorage.getItem('auth-storage'); if (authStorage) { const parsed = JSON.parse(authStorage); @@ -244,7 +252,7 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo localStorage.setItem('auth-storage', JSON.stringify(parsed)); } } catch (e) { - // Ignore storage errors + console.warn('Failed to update token after refresh:', e); } // Retry original request with new token