Plataforma técnica · Seguridad
Autenticación y Autorización
Seguridad
Orchestrator combina JWT firmado con una sesión persistida en auth.user_sessions. El JWT no basta por sí solo: cada solicitud protegida debe validar que el token existe, que la firma es válida, que contiene sessionId y que la sesión sigue vigente en la base central.
Flujo de Login
Section titled “Flujo de Login”- Sevastopol envía
username,passwordy opcionalmenterememberMeaPOST /api/auth/login. loginRateLimiterlimita intentos fallidos antes de ejecutar la validación de credenciales.- Orchestrator valida el payload con
express-validatory busca el usuario enauth.users. - La contraseña se compara con
bcryptjs.comparecontrapassword_hash. - Si el usuario tiene TOTP habilitado, la respuesta entrega
requires_2faytemp_token; no se emite sesión todavía. - Si no requiere TOTP, o si
POST /api/auth/2fa/verifyconfirma el desafío, Orchestrator insertaauth.user_sessions, firma el JWT y emite la cookiesid.
sequenceDiagram
participant User as Usuario
participant UI as Sevastopol
participant API as Orchestrator
participant Auth as auth.users
participant Sessions as auth.user_sessions
participant TOTP as TotpService
User->>UI: Ingresa credenciales
UI->>API: POST /api/auth/login
API->>Auth: SELECT user por username
API->>API: bcryptjs.compare(password, password_hash)
alt TOTP habilitado
API->>TOTP: Crear desafío temporal
API-->>UI: requires_2fa + temp_token
UI->>API: POST /api/auth/2fa/verify
API->>TOTP: Verificar código o backup code
end
API->>Sessions: INSERT session_id, user_id, ip, user_agent, expires_at
API-->>UI: Set-Cookie sid=JWT HttpOnly
UI-->>User: Sesión iniciada Token y Cookie
Section titled “Token y Cookie”El payload contiene identidad y contexto mínimo de sesión. No debe contener secretos, permisos derivados ni datos personales innecesarios.
{ "userId": "$USER_ID", "username": "$USERNAME", "role": "ADMIN", "sessionId": "$SESSION_ID", "tenantId": "$TENANT_ID", "iat": 1780000000, "exp": 1780086400}| Campo | Uso |
|---|---|
userId | Identificador del usuario autenticado |
username | Nombre de usuario para contexto y respuesta |
role | Rol base para RBAC |
sessionId | Llave de revocación contra auth.user_sessions |
tenantId | Tenant asignado al usuario, cuando aplica |
iat / exp | Emisión y expiración del JWT |
La sesión se entrega como cookie sid con HttpOnly, SameSite=Lax, path=/ y Secure en producción.
Set-Cookie: sid=$JWT; Path=/; HttpOnly; SameSite=Lax; Secure; Max-Age=86400rememberMe aumenta la duración desde 24 horas a 30 días. La expiración también se persiste en auth.user_sessions.expires_at, por lo que una cookie vieja no reactiva una sesión eliminada o vencida.
POST /api/auth/logout elimina la sesión actual de auth.user_sessions y limpia la cookie. El módulo Command Sessions permite terminar sesiones activas por id cuando se requiere respuesta operativa.
Validación de Solicitudes Protegidas
Section titled “Validación de Solicitudes Protegidas”authenticateToken vive en orchestrator/src/middleware/auth.ts. Extrae el token desde Authorization: Bearer $TOKEN o desde la cookie sid, valida la firma con $JWT_SECRET, consulta auth.user_sessions y carga req.user.
export const authenticateToken = async (req, res, next) => { const token = extractTokenFromRequest(req);
if (!token) { return res.status(401).json({ success: false, error: 'No authorization token' }); }
const session = await validateSessionToken(token);
if (!session) { clearSessionCookie(res); return res.status(401).json({ success: false, error: 'Invalid, expired, or revoked session', }); }
req.user = session; next();};Autorización RBAC
Section titled “Autorización RBAC”La autenticación responde quién es el usuario. La autorización responde qué puede hacer. Orchestrator usa dos mecanismos complementarios:
| Mecanismo | Ubicación | Uso esperado |
|---|---|---|
authorizeRoute | middleware/auth.ts con lib/rbac.ts | Proteger rutas declaradas en el mapa RBAC por rol |
requireRole | middleware/auth.ts y lib/rbac.ts | Restringir operaciones específicas a uno o más roles |
| Reglas de dominio | Servicios y repositorios | Validar condiciones funcionales que RBAC no puede expresar |
| Rol | Alcance documentado | Ejemplos de acceso |
|---|---|---|
SUPER_ADMIN | Administración global y operaciones multi-tenant explícitas | Tenants, usuarios, sesiones, monitoreo, administración y reportes |
ADMIN | Administración del tenant asignado | Contabilidad, operaciones, administración de empresa y reportes |
USER | Operación acotada y lectura | Lectura contable, operaciones permitidas y reportes |
router.post( '/', authenticateToken, requireRole(['ADMIN', 'SUPER_ADMIN']), async (req, res) => { // Operación protegida por identidad y rol explícito. },);Segundo Factor
Section titled “Segundo Factor”TOTP se implementa en domain/auth/totp y se integra con routes/command/auth.ts.
| Endpoint | Protección | Propósito |
|---|---|---|
POST /api/auth/2fa/setup | authenticateToken | Iniciar configuración de TOTP para el usuario autenticado |
POST /api/auth/2fa/enable | authenticateToken | Confirmar código TOTP y activar segundo factor |
POST /api/auth/2fa/disable | authenticateToken | Desactivar TOTP con código actual o backup code |
POST /api/auth/2fa/verify | Desafío temporal | Convertir temp_token y código válido en sesión real |
Auditoría de Identidad
Section titled “Auditoría de Identidad”El flujo de autenticación registra eventos mediante auditLog:
| Evento | Cuándo se emite |
|---|---|
LOGIN | Credenciales válidas y sesión creada |
LOGIN_FAILED | Usuario inexistente o contraseña inválida |
LOGOUT | Sesión eliminada durante logout |
API_ACCESS | Mutaciones o errores relevantes en rutas autenticadas |
Los eventos incluyen IP, user agent y contexto de usuario cuando está disponible. Los campos sensibles se deben sanitizar antes de persistirse en auditoría.