Autenticación y Seguridad
Floutic implementa un sistema de autenticación robusto con múltiples capas de seguridad, siguiendo las mejores prácticas de la industria.
Sistema de Autenticación JWT
Tokens
Floutic utiliza un sistema dual de tokens:
-
Access Token (JWT)
- Almacenado en memoria (no en localStorage)
- Vida corta (15 minutos por defecto)
- Incluye información del usuario y
session_id - Enviado en header
Authorization: Bearer <token>
-
Refresh Token
- Almacenado en cookie HttpOnly
- Vida larga (7 días por defecto)
- Usado para renovar access tokens
- No accesible desde JavaScript
Endpoints de Autenticación
Login Seguro
POST /api/auth/login_secure
Request:
{
"username": "usuario@ejemplo.com",
"password": "contraseña_segura"
}
Headers requeridos:
X-Session-ID: ID único de sesión generado por el cliente
Response:
{
"access_token": "eyJ...",
"csrf_token": "csrf_...",
"user": {
"id": 1,
"email": "usuario@ejemplo.com",
"username": "usuario",
"role": "empresa"
}
}
Cookies establecidas:
refresh_token: HttpOnly, SameSite=Strictcsrf_token: HttpOnly, SameSite=Strict
Refresh Token
POST /api/auth/refresh_secure
Headers requeridos:
X-Session-ID: Debe coincidir con el del token- Cookie:
refresh_token
Response:
{
"access_token": "eyJ...",
"csrf_token": "csrf_..."
}
Verificar Sesión
GET /api/auth/verify_secure
Headers requeridos:
X-Session-ID: Debe coincidir con el del token- Cookie:
refresh_token
Response:
{
"valid": true,
"authenticated": true,
"user": {
"id": 1,
"email": "usuario@ejemplo.com",
"username": "usuario",
"role": "empresa"
},
"access_token": "eyJ...",
"csrf_token": "csrf_..."
}
Logout
POST /api/auth/logout_secure
Headers requeridos:
X-Session-ID- Cookie:
refresh_token X-CSRF-Token: Token CSRF
Response:
{
"message": "Logout successful"
}
Protección CSRF
Implementación
Floutic implementa protección CSRF con tokens HttpOnly:
-
Token CSRF en Cookie
- Generado en login/refresh
- Almacenado en cookie HttpOnly
- Incluido en respuesta JSON
-
Validación en Servidor
- Todos los requests mutantes (POST, PUT, DELETE, PATCH) requieren CSRF token
- Token debe estar en header
X-CSRF-Token - Token debe coincidir con el de la cookie
-
Renovación
- Token se renueva en cada refresh
- Token se invalida en logout
Uso en Frontend
// El cliente Axios añade automáticamente el CSRF token
const response = await api.post('/api/projects', data);
// Header X-CSRF-Token se añade automáticamente
Session ID Único
Propósito
El session_id único por ventana previene la fuga de sesiones entre ventanas privadas.
Implementación
-
Generación en Cliente
- Cada ventana genera un
session_idúnico - Almacenado en
sessionStorage(aislado entre ventanas) - Formato:
sess_<random>
- Cada ventana genera un
-
Inclusión en JWT
- El
session_idse incluye en el payload del JWT - Validado en cada request
- El
-
Validación en Servidor
login_secure: LeeX-Session-IDdel header, lo incluye en JWTrefresh_secure: Valida quesession_iddel header coincida con el del tokenverify_secure: Valida quesession_iddel header coincida con el del token
Flujo
┌─────────────────────────────────────┐
│ VENTANA 1 │
│ 1. Genera session_id: sess_abc123 │
│ 2. Login → JWT incluye sess_abc123 │
│ 3. Cookie creada con JWT │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ VENTANA 2 │
│ 1. Genera session_id: sess_xyz789 │
│ 2. Aunque tenga cookie compartida...│
│ 3. verify_secure compara: │
│ - Token: sess_abc123 │
│ - Header: sess_xyz789 │
│ - ❌ NO COINCIDEN → RECHAZADO │
└─────────────────────────────────────┘
Cookies Seguras
Configuración
Desarrollo:
domain=None # Sin domain para máximo aislamiento
secure=False # HTTP permitido en localhost
samesite="strict" # Aislamiento máximo entre contextos
httponly=True # No accesible desde JavaScript
Producción:
domain="floutic.com" # Para permitir subdominios
secure=True # Solo HTTPS
samesite="strict" # Aislamiento máximo
httponly=True # No accesible desde JavaScript
Cookies Utilizadas
-
refresh_token
- HttpOnly, SameSite=Strict
- Vida: 7 días (configurable)
- Usado para renovar access tokens
-
csrf_token
- HttpOnly, SameSite=Strict
- Vida: 7 días (configurable)
- Usado para protección CSRF
Sesiones Concurrentes
Límites
- Máximo 10 sesiones concurrentes por usuario individual
- Sin límite para usuarios de empresa (múltiples usuarios pueden estar logueados simultáneamente)
Configuración
MAX_CONCURRENT_SESSIONS = 10 # Configurable via env var
Gestión
- Las sesiones se rastrean en Redis
- Al exceder el límite, la sesión más antigua se invalida
- El usuario recibe notificación de sesión expirada
Rate Limiting
Niveles
- Global: 60 requests/minuto por IP
- Login por Usuario: 5 intentos máximo
- Login por IP: 20 intentos máximo
Implementación
# Global rate limiting
@limiter.limit("60/minute")
# Login rate limiting
@limiter.limit("5/minute", key_func=lambda: f"login_user_{user_id}")
@limiter.limit("20/minute", key_func=lambda: f"login_ip_{ip}")
Respuestas
- 429 Too Many Requests: Cuando se excede el límite
- Retry-After: Header con tiempo de espera
- Frontend muestra mensaje apropiado al usuario
Validación de Contraseñas
Requisitos
- Mínimo 8 caracteres
- Al menos una mayúscula
- Al menos una minúscula
- Al menos un número
- Al menos un carácter especial
Hash
- bcrypt con salt rounds = 12
- Nunca se almacenan contraseñas en texto plano
RBAC (Role-Based Access Control)
Roles
- admin: Acceso completo al sistema
- empresa: Gestión de proyectos y pagos
- experto: Aplicación a proyectos y gestión de hitos
Implementación
@router.get("/admin/users")
@require_role("admin")
async def get_users():
# Solo admins pueden acceder
pass
Más Información
- Cookies - Seguridad de cookies y sesiones
- Headers - Security headers implementados
- Verificación - Sistema de verificación
- Frontend - Autenticación - Autenticación en frontend