Autenticación Frontend
Floutic implementa un sistema de autenticación seguro con múltiples capas de protección, utilizando HttpOnly cookies, CSRF tokens y session IDs únicos.
Sistema de Autenticación Segura
Características Principales
- ✅ HttpOnly cookies: Tokens almacenados de forma segura
- ✅ CSRF protection: Tokens CSRF en cookies HttpOnly
- ✅ Session ID único: Por ventana para aislar sesiones
- ✅ Refresh automático: Renovación transparente de tokens
- ✅ Logout por inactividad: Configurable por rol
- ✅ Validación de session_id: En todas las peticiones
Implementación
Servicio de Autenticación (src/lib/auth/secureAuth.ts)
Métodos Principales
class SecureAuthService {
// Login con credenciales
async login(credentials: { username: string; password: string }): Promise<void>
// Logout seguro
async logout(): Promise<void>
// Verificar sesión actual
async verifySession(): Promise<boolean>
// Refresh automático de tokens
async refreshToken(): Promise<void>
// Obtener usuario actual
getCurrentUser(): User | null
}
Session ID Único
Cada ventana genera un session_id único:
- Almacenado en
sessionStorage(aislado entre ventanas privadas) - Enviado en header
X-Session-IDen cada petición - Incluido en el payload del JWT al crear tokens
- Validado en el servidor para prevenir fuga de sesiones
Hook de Autenticación (useSecureAuth)
Hook principal para usar autenticación en componentes:
const {
user,
isAuthenticated,
isLoading,
login,
logout,
verifySession
} = useSecureAuth();
Características:
- Estado reactivo de autenticación
- Inicialización automática al montar
- Refresh automático de tokens
- Manejo de errores
Cliente API
El cliente Axios (src/lib/api/client.ts) incluye interceptores:
Request Interceptor
- Añade
X-Session-IDheader - Añade
X-CSRF-Tokenheader - Añade
Authorizationheader con access token
Response Interceptor
- Maneja errores 401 (no autorizado)
- Refresh automático de tokens
- Retry logic para requests fallidos
Flujo de Autenticación
Login
- Usuario ingresa credenciales
- Frontend envía
POST /api/auth/login_securecon:usernameypassword- Header
X-Session-ID(generado en cliente)
- Backend valida credenciales y crea:
refresh_tokenen cookie HttpOnlycsrf_tokenen cookie HttpOnlyaccess_tokenen respuesta JSON- JWT incluye
session_iddel header
- Frontend almacena:
access_tokenen memoria (no localStorage)session_iden sessionStorage- Estado de autenticación en Zustand store
Verificación de Sesión
- Al cargar la app, se llama a
verify_secure - Backend valida:
refresh_tokenen cookiessession_iddel header coincide con el del token
- Si es válido, devuelve usuario y tokens
- Frontend actualiza estado de autenticación
Refresh de Tokens
- Cuando el
access_tokenexpira (o está próximo a expirar) - Frontend llama a
POST /api/auth/refresh_secure - Backend valida:
refresh_tokenen cookiessession_iddel header
- Genera nuevos tokens y los devuelve
- Frontend actualiza
access_tokenen memoria
Logout
- Usuario hace logout
- Frontend llama a
POST /api/auth/logout_secure - Backend:
- Invalida
refresh_tokenen Redis blacklist - Elimina cookies
- Invalida
- Frontend:
- Limpia estado de autenticación
- Limpia
session_idde sessionStorage - Redirige a login
Protección de Rutas
Middleware de Astro (src/middleware.ts)
El middleware verifica autenticación antes de servir páginas:
export async function onRequest(context, next) {
const { url, cookies } = context;
// Rutas públicas
if (isPublicRoute(url.pathname)) {
return next();
}
// Verificar autenticación
const authenticated = await verifyAuth(cookies);
if (!authenticated) {
return redirect('/login');
}
return next();
}
Protección de Componentes
Componentes protegidos verifican autenticación:
const Dashboard = () => {
const { isAuthenticated, isLoading } = useSecureAuth();
if (isLoading) return <Loading />;
if (!isAuthenticated) return <Redirect to="/login" />;
return <DashboardContent />;
};
Seguridad
HttpOnly Cookies
refresh_token: Token de renovación (HttpOnly, SameSite=Strict)csrf_token: Token CSRF (HttpOnly, SameSite=Strict)
Configuración:
- Desarrollo:
domain=None,secure=False,SameSite=Strict - Producción:
domain="floutic.com",secure=True,SameSite=Strict
CSRF Protection
- Token CSRF en cookie HttpOnly
- Token enviado en header
X-CSRF-Token - Validación en servidor para requests mutantes (POST, PUT, DELETE, PATCH)
Session ID Único
- Generado por ventana en
sessionStorage - Enviado en header
X-Session-ID - Validado en servidor para aislar sesiones entre ventanas privadas
Aislamiento de Sesiones
Triple protección:
- Cookies con
SameSite=Strict(aislamiento a nivel de cookies) - Sin
domainen desarrollo (aislamiento a nivel de origen) - Validación de
session_idúnico (aislamiento a nivel de aplicación)
Logout por Inactividad
Configuración
const IDLE_TIMEOUTS = {
admin: 30 * 60 * 1000, // 30 minutos
empresa: 60 * 60 * 1000, // 1 hora
experto: 60 * 60 * 1000, // 1 hora
};
Hook useIdleTimeout
useIdleTimeout({
timeout: IDLE_TIMEOUTS[user.role],
onIdle: () => {
logout();
showWarning('Sesión expirada por inactividad');
}
});
Almacenamiento
sessionStorage
session_id: ID único por ventana- Aislado entre ventanas privadas
Memoria (no persistente)
access_token: Token de acceso actual- Se pierde al recargar la página
Cookies (HttpOnly)
refresh_token: Token de renovacióncsrf_token: Token CSRF
Más Información
- Seguridad - Autenticación - Documentación completa de seguridad
- Seguridad - Cookies - Seguridad de cookies y sesiones
- Arquitectura - Arquitectura del frontend