Autenticación y Autorización
El sistema Nostromo utiliza JSON Web Tokens (JWT) para la autenticación stateless y Role-Based Access Control (RBAC) para la autorización granular.
Mecanismo de Autenticación
Section titled “Mecanismo de Autenticación”A diferencia de sistemas tradicionales basados en sesión, Nostromo utiliza un enfoque Token-Based:
- Frontend envía credenciales (
email,password) al endpoint/auth/login - Backend valida contra hash en BD usando
bcrypt - Backend retorna un JWT firmado con
JWT_SECRET - Frontend almacena token en cookie
sid(httpOnly) - Requests subsiguientes incluyen token automáticamente
Flujo de Secuencia
Section titled “Flujo de Secuencia”%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#2a2a2a', 'primaryTextColor': '#e0e0e0', 'lineColor': '#f38020'}}}%%
sequenceDiagram
participant U as 👤 Usuario
participant F as 🏝️ Sevastopol
participant A as 🎯 Orchestrator
participant D as 🗄️ PostgreSQL
U->>F: Ingresa credenciales
F->>A: POST /auth/login
A->>D: SELECT * FROM auth.users WHERE email=$1
D-->>A: User Hash
A->>A: bcrypt.compare(pass, hash)
alt ✅ Credenciales válidas
A->>A: Generar JWT (sign)
A-->>F: { token, user_data }
Note over A,F: Set-Cookie: sid=<JWT>
F->>U: Redirige al Dashboard
else ❌ Inválidas
A-->>F: 401 Unauthorized
F->>U: Muestra error
end
Estructura del Token
Section titled “Estructura del Token”El JWT contiene información para el contexto de la solicitud, pero no contiene secretos:
{ "userId": "uuid-v4-del-usuario", "role": "ADMIN", "iat": 1703698000, "exp": 1703784400}| Campo | Descripción |
|---|---|
userId | UUID único del usuario |
email | Email para logging/audit |
role | Rol global (SUPER_ADMIN, ADMIN, USER, RO) |
iat | Timestamp de emisión |
exp | Expiración (24h por defecto) |
En producción, el token se almacena en una cookie segura:
Set-Cookie: sid=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...; Path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=86400Middleware de Protección
Section titled “Middleware de Protección”El backend utiliza un middleware authenticateToken que intercepta todas las rutas protegidas:
import jwt from 'jsonwebtoken';import cookie from 'cookie';
export const authenticateToken = (req, res, next) => { // 1. Intentar obtener token del header Authorization const authHeader = req.headers['authorization']; let token = authHeader?.split(' ')[1]; // Bearer TOKEN
// 2. Fallback: buscar en cookie sid if (!token && req.headers.cookie) { const parsed = cookie.parse(req.headers.cookie); token = parsed.sid; }
if (!token) { return res.status(401).json({ success: false, error: 'No authorization token' }); }
try { const decoded = jwt.verify(token, process.env.JWT_SECRET!); req.user = decoded; // Inyecta usuario en el request next(); } catch { return res.status(403).json({ success: false, error: 'Invalid or expired token' }); }};Roles y Permisos (RBAC)
Section titled “Roles y Permisos (RBAC)”Aunque el JWT valida la identidad, los permisos específicos se validan mediante el sistema RBAC:
| Rol | Alcance | Descripción |
|---|---|---|
| SUPER_ADMIN | 🌍 Global | Acceso total a todos los tenants y configuración de sistema |
| ADMIN | 🏢 Tenant | Acceso total dentro de su organización |
| USER | 🏢 Tenant | Acceso estándar para operar módulos |
| RO | 🏢 Tenant | Solo lectura para auditores |
export const authorizeRoute = (req, res, next) => { const { role } = req.user; const route = req.originalUrl.split('?')[0];
if (!rbac.canAccess(role, route)) { return res.status(403).json({ success: false, error: `Access denied for role '${role}'` }); } next();};import { authenticateToken, authorizeRoute } from '@/middleware/auth';
// Solo SUPER_ADMIN puede eliminar tenantsrouter.delete('/', authenticateToken, authorizeRoute, async (req, res) => { // ... lógica de eliminación });