diff --git a/components/AuthIndicator.client.vue b/components/AuthIndicator.client.vue index 8136a1f..bedbfe0 100644 --- a/components/AuthIndicator.client.vue +++ b/components/AuthIndicator.client.vue @@ -66,8 +66,16 @@ watch(() => musicStore.error, (error, oldError) => { if (error && error !== oldError) { console.log('[AuthIndicator] Music store error detected:', error) - if (error.includes('401') || error.includes('403') || - error.includes('Unauthorized') || error.includes('Forbidden')) { + // Detectar errores de autenticación (múltiples formas) + const isAuthError = + error.includes('401') || + error.includes('403') || + error.includes('Unauthorized') || + error.includes('Forbidden') || + error.includes('Failed to fetch') || // Authentik redirect genera esto + error.includes('no response') // Nuxt $fetch sin respuesta + + if (isAuthError) { // Auth error detected - mark as unauthenticated immediately console.log('[AuthIndicator] Auth error detected, updating status') markUnauthenticated() @@ -80,8 +88,15 @@ watch(() => musicStore.loading, (loading, wasLoading) => { if (wasLoading && !loading && musicStore.error) { // Terminó de cargar con error, verificar si es de auth const error = musicStore.error - if (error.includes('401') || error.includes('403') || - error.includes('Unauthorized') || error.includes('Forbidden')) { + const isAuthError = + error.includes('401') || + error.includes('403') || + error.includes('Unauthorized') || + error.includes('Forbidden') || + error.includes('Failed to fetch') || + error.includes('no response') + + if (isAuthError) { markUnauthenticated() } } diff --git a/composables/useAuth.ts b/composables/useAuth.ts index 84efc6f..e687f3e 100644 --- a/composables/useAuth.ts +++ b/composables/useAuth.ts @@ -48,20 +48,37 @@ export const useAuth = () => { console.log('[Auth] Status changed:', isAuthenticated.value ? 'authenticated' : 'unauthenticated') } } catch (error: any) { - // TypeError: Failed to fetch = probablemente redirect de Authentik (no autenticado) - // o error de red real + // Con redirect: 'error', cualquier redirect (302) genera "Failed to fetch" + // Authentik redirige a login cuando no estás autenticado = 302 console.warn('[Auth] Check failed:', error.message) - // Si el error es por redirect (Authentik intenta redirigir a login), no estamos autenticados - if (error.message && error.message.includes('redirect')) { - const wasAuthenticated = isAuthenticated.value + const wasAuthenticated = isAuthenticated.value + + // "Failed to fetch" con redirect: 'error' configurado = sesión expirada + // Authentik intenta redirigir (302) pero fetch lo rechaza y genera error + if (error.message && error.message.includes('Failed to fetch')) { + console.log('[Auth] Failed to fetch detected - marking as unauthenticated') isAuthenticated.value = false authChecked.value = true if (wasAuthenticated) { - console.log('[Auth] Status changed: unauthenticated (redirect detected)') + console.log('[Auth] Status changed: authenticated → unauthenticated (Authentik redirect detected)') + } else { + console.log('[Auth] Confirmed unauthenticated state') } + } else if (error.name === 'TypeError' && error.message.includes('fetch')) { + // Otro tipo de TypeError fetch = también probablemente redirect + console.log('[Auth] TypeError fetch detected - marking as unauthenticated') + isAuthenticated.value = false + authChecked.value = true + if (wasAuthenticated) { + console.log('[Auth] Status changed: authenticated → unauthenticated (fetch error)') + } else { + console.log('[Auth] Confirmed unauthenticated state') + } + } else { + // Otro tipo de error (timeout, etc) - mantener estado actual + console.log('[Auth] Network error (not auth related), maintaining current state:', error.name) } - // Si no, mantenemos el estado actual (puede ser error de red temporal) lastCheckTime.value = now } finally {