- Detect CORS/redirect errors from Authentik and interpret them as "no session" instead of generic error - When session expires, Authentik returns 302 redirect to login which causes CORS error in fetch requests - Add /api/_nuxt_icon/ to public routes to prevent icon load failures after logout This fixes the issue where logout in Authentik showed "Error" instead of "Sin Sesión" when checking session status.
127 lines
4.0 KiB
TypeScript
127 lines
4.0 KiB
TypeScript
/**
|
|
* Composable para leer información de usuario de Authentik
|
|
* Los headers son inyectados por Authentik Proxy Outpost
|
|
*/
|
|
export const useAuthentik = () => {
|
|
// Leer headers en el servidor y almacenarlos en state
|
|
const authentikUser = useState('authentikUser', () => {
|
|
// Solo en el servidor, leer los headers
|
|
if (process.server) {
|
|
const headers = useRequestHeaders()
|
|
|
|
const username = headers['x-authentik-username']
|
|
const email = headers['x-authentik-email']
|
|
const name = headers['x-authentik-name']
|
|
const groups = headers['x-authentik-groups']
|
|
const uid = headers['x-authentik-uid']
|
|
|
|
// Si no hay username, el usuario no está autenticado
|
|
if (!username) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
username,
|
|
email,
|
|
name,
|
|
groups: groups ? groups.split('|') : [],
|
|
uid,
|
|
// Generar avatar URL usando UI Avatars
|
|
avatar: `https://ui-avatars.com/api/?name=${encodeURIComponent(name || username)}&background=random&size=128`
|
|
}
|
|
}
|
|
|
|
return null
|
|
})
|
|
|
|
const user = computed(() => authentikUser.value)
|
|
const isAuthenticated = computed(() => !!user.value)
|
|
|
|
const logout = () => {
|
|
// Logout completo: invalida la sesión de Authentik completamente
|
|
// Esto cierra sesión en todas las aplicaciones
|
|
const authentikUrl = useRuntimeConfig().public.authentikUrl || 'https://authentik.nucleoriofrio.com'
|
|
navigateTo(`${authentikUrl}/flows/-/default/invalidation/`, { external: true })
|
|
}
|
|
|
|
const goToProfile = () => {
|
|
// URL de perfil de Authentik
|
|
const authentikUrl = useRuntimeConfig().public.authentikUrl || 'https://authentik.nucleoriofrio.com'
|
|
navigateTo(`${authentikUrl}/if/user/`, { external: true, open: { target: '_blank' } })
|
|
}
|
|
|
|
const checkSessionStatus = async () => {
|
|
const toast = useToast()
|
|
|
|
// Mostrar toast de "verificando..."
|
|
toast.add({
|
|
title: 'Verificando sesión...',
|
|
description: 'Consultando estado en Authentik',
|
|
color: 'info',
|
|
icon: 'i-heroicons-arrow-path',
|
|
timeout: 2000
|
|
})
|
|
|
|
try {
|
|
// Consultar el endpoint de API que verifica contra Authentik
|
|
const response = await $fetch('/api/auth/status')
|
|
|
|
if (response.authenticated && response.user) {
|
|
// Sesión activa en Authentik
|
|
toast.add({
|
|
title: 'Sesión Activa',
|
|
description: `Conectado como: ${response.user.name || response.user.username}`,
|
|
color: 'success',
|
|
icon: 'i-heroicons-check-circle',
|
|
timeout: 5000
|
|
})
|
|
} else {
|
|
// Sin sesión en Authentik
|
|
toast.add({
|
|
title: 'Sin Sesión',
|
|
description: 'No hay sesión activa en Authentik',
|
|
color: 'warning',
|
|
icon: 'i-heroicons-exclamation-triangle',
|
|
timeout: 5000
|
|
})
|
|
}
|
|
} catch (error) {
|
|
// Si el error es por redirect de Authentik (CORS/fetch error), significa que no hay sesión
|
|
// Authentik redirige a login cuando no hay sesión válida, causando error CORS en fetch
|
|
const errorMessage = error?.message || error?.toString() || ''
|
|
const isCorsOrRedirectError = errorMessage.includes('Failed to fetch') ||
|
|
errorMessage.includes('CORS') ||
|
|
error?.statusCode === 302
|
|
|
|
if (isCorsOrRedirectError) {
|
|
// Interpretar como sesión expirada/inválida
|
|
toast.add({
|
|
title: 'Sin Sesión',
|
|
description: 'No hay sesión activa en Authentik',
|
|
color: 'warning',
|
|
icon: 'i-heroicons-exclamation-triangle',
|
|
timeout: 5000
|
|
})
|
|
} else {
|
|
// Error real de red o servidor
|
|
toast.add({
|
|
title: 'Error',
|
|
description: 'No se pudo verificar el estado de la sesión',
|
|
color: 'error',
|
|
icon: 'i-heroicons-x-circle',
|
|
timeout: 5000
|
|
})
|
|
}
|
|
console.error('Error checking session status:', error)
|
|
}
|
|
}
|
|
|
|
return {
|
|
user,
|
|
isAuthenticated,
|
|
logout,
|
|
goToProfile,
|
|
checkSessionStatus
|
|
}
|
|
}
|