From b46d15145f2f25a8c7d58f02ce9e9730f37cd349 Mon Sep 17 00:00:00 2001 From: josedario87 Date: Fri, 17 Oct 2025 03:40:12 -0600 Subject: [PATCH] =?UTF-8?q?fix:=20evitar=20error=20CORS=20al=20expirar=20s?= =?UTF-8?q?esi=C3=B3n=20de=20Authentik?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cuando la sesión de Authentik expira, los fetch() a /api/music recibían un redirect (302) a la página de login. Por defecto, fetch intenta seguir el redirect pero falla por CORS porque Authentik no tiene el header Access-Control-Allow-Origin. La solución es usar redirect: 'error' en todos los fetch() a endpoints protegidos, lo que convierte los redirects en errores que podemos capturar y manejar apropiadamente. Esto coincide con la estrategia que ya usa useAuth.ts. Cambios: - stores/music.ts: Agregar redirect: 'error' a fetchTracks() y cacheByName() - pages/index.vue: Agregar redirect: 'error' a playTrack() - Mejorar detección de errores de autenticación para incluir 'Failed to fetch' y errores de tipo TypeError relacionados con redirects --- pages/index.vue | 14 +++++++++++--- stores/music.ts | 28 ++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/pages/index.vue b/pages/index.vue index c08353b..afc8f2a 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -197,7 +197,10 @@ const playTrack = async (track, index) => { // Fetch and preload entire song into memory const encodedName = encodeURIComponent(track.name) - const response = await fetch(`/api/music/${encodedName}`) + const response = await fetch(`/api/music/${encodedName}`, { + credentials: 'include', + redirect: 'error' // No seguir redirects de Authentik - convertir en error + }) // Check for authentication errors if (!response.ok) { @@ -235,8 +238,13 @@ const playTrack = async (track, index) => { loadingTrack.value = null // Don't try fallback streaming if it's an auth error (it will fail too) - if (error.message && (error.message.includes('401') || error.message.includes('403'))) { - console.warn('[PlayTrack] Skipping fallback due to auth error') + // Esto incluye errores de redirect de Authentik + if (error.message && (error.message.includes('401') || + error.message.includes('403') || + error.message.includes('Failed to fetch') || + (error.name === 'TypeError' && error.message.includes('redirect')))) { + console.warn('[PlayTrack] Skipping fallback due to auth error:', error.message) + musicStore.error = error.message || 'Authentication error' return } diff --git a/stores/music.ts b/stores/music.ts index 16bdf97..97f79c5 100644 --- a/stores/music.ts +++ b/stores/music.ts @@ -44,17 +44,22 @@ export const useMusicStore = defineStore('music', { this.loading = true this.error = null try { - const response = await $fetch<{ tracks: Track[] }>('/api/music') + const response = await $fetch<{ tracks: Track[] }>('/api/music', { + credentials: 'include', + redirect: 'error' // No seguir redirects de Authentik - convertir en error + }) this.tracks = response.tracks || [] } catch (e: any) { const errorMsg = e?.message || 'Failed to load tracks' this.error = errorMsg - // Check if it's an auth error + // Check if it's an auth error (including redirect attempts from Authentik) if (e?.statusCode === 401 || e?.statusCode === 403 || errorMsg.includes('401') || errorMsg.includes('403') || - errorMsg.includes('Unauthorized')) { - console.warn('[Music Store] Authentication error detected') + errorMsg.includes('Unauthorized') || + errorMsg.includes('Failed to fetch') || + (e?.cause?.name === 'TypeError' && e?.cause?.message?.includes('redirect'))) { + console.warn('[Music Store] Authentication error detected:', errorMsg) // The useAuth composable will be notified via watch in components } } finally { @@ -128,7 +133,10 @@ export const useMusicStore = defineStore('music', { async cacheByName(name: string, duration?: number): Promise { try { const encodedName = encodeURIComponent(name) - const response = await fetch(`/api/music/${encodedName}`) + const response = await fetch(`/api/music/${encodedName}`, { + credentials: 'include', + redirect: 'error' // No seguir redirects de Authentik - convertir en error + }) if (!response.ok) { const errorMsg = `HTTP ${response.status}` @@ -147,9 +155,13 @@ export const useMusicStore = defineStore('music', { return true } catch (e: any) { console.error('[Music Store] Cache failed:', e) - // Propagate auth errors - if (e?.message?.includes('401') || e?.message?.includes('403')) { - this.error = e.message + + // Propagate auth errors (including redirect attempts from Authentik) + if (e?.message?.includes('401') || + e?.message?.includes('403') || + e?.message?.includes('Failed to fetch') || + (e?.name === 'TypeError' && e?.message?.includes('redirect'))) { + this.error = e.message || 'Authentication error' } return false }