02 · Autenticación JWT
MAG-02-AUTH · Autenticación JWT
Una identidad. Un token. Una empresa.
Toda petición autenticada a Roustix se realiza mediante JSON Web Token (JWT). El token identifica al usuario, la empresa (tenant) y el rol, evitando que el cliente tenga que enviar información sensible en cada solicitud.
La autenticación no solo valida quién es el usuario; también determina qué empresa está usando, qué módulos tiene activos y qué permisos posee.
1 · Flujo de autenticación
Login
│
▼
Usuario + contraseña + empresa
│
▼
Validación
│
▼
JWT firmado
│
▼
Cliente almacena token
│
▼
Authorization: Bearer <token>
│
▼
API Roustix
2 · Endpoint oficial
POST /api/v1/auth/login
Content-Type: application/json
Ruta actual (legacy): POST /api/auth/login
Request
{
"username": "ana.garcia",
"password": "********",
"empresa_slug": "empresa-xyz"
}
Respuesta exitosa (200)
{
"token": "<jwt>",
"expires_in": 28800,
"user": {
"id": 15,
"nombre": "Ana García",
"rol": "admin"
},
"empresa": {
"id": 4,
"slug": "empresa-xyz",
"nombre": "Empresa XYZ"
}
}
| Campo | Descripción |
|---|---|
token | JWT firmado (ver §4) |
expires_in | Segundos hasta expiración (28800 = 8 h por defecto) |
user | Identidad y rol del usuario |
empresa | Tenant activo tras login |
3 · Header estándar
Todas las solicitudes autenticadas utilizan:
Authorization: Bearer eyJhbGc...
JWT y API keys de integración se transportan como Bearer. El prefijo de la
credencial permite seleccionar el validador sin cambiar el header. No se
aceptan credenciales en query string ni Basic Auth. Las API keys se implementan
conforme al contrato de permisos de la plataforma.
4 · Parámetros de firma
| Parámetro | Valor |
|---|---|
| Algoritmo | HS256 |
| Firma | clave de firma del servidor |
| Expiración | 8 h por defecto · configurable |
| Clock skew | ±30 s recomendado |
5 · Payload del JWT
El token contiene únicamente la información necesaria para identificar el contexto de operación.
| Campo | Descripción | Obligatorio v1 |
|---|---|---|
sub | ID del usuario | Sí |
empresa_id | Empresa del usuario | Sí |
empresa_slug | Identificador público de la empresa | Sí |
rol | Rol principal | Sí |
plan | Plan contratado (start, grow, scale, …) | Sí* |
modules | Módulos activos del tenant | Sí* |
auth_version | Versión revocable de identidad | Sí |
jti | Identificador único del token | Sí |
iat | Fecha de emisión (Unix timestamp) | Sí |
nbf | Inicio de validez | Sí |
exp | Fecha de expiración (Unix timestamp) | Sí |
Ejemplo
{
"sub": 15,
"empresa_id": 4,
"empresa_slug": "empresa-xyz",
"rol": "admin",
"plan": "grow",
"modules": ["maintenance", "inventory"],
"iat": 1783670400,
"exp": 1783756800
}
El servidor nunca confía en empresa_id enviado en query o body si contradice el token.
En cada petición, Roustix revalida auth_version, usuario activo, empresa, slug
y rol contra PostgreSQL. Cambiar contraseña, bloquear o mover al usuario revoca
inmediatamente los JWT emitidos anteriormente.
Claims reservados
Roustix reserva los siguientes claims para futuras versiones. No deben ser usados por integradores:
| Claim | Uso previsto |
|---|---|
tenant_type | Tipo de tenant (empresa, partner, sandbox) |
permissions | Permisos granulares más allá del rol |
locale | Locale preferido del usuario |
timezone | Zona horaria IANA del tenant |
features | Feature flags activos |
Esto evita romper el contrato cuando se añadan capacidades sin bump de versión JWT.
6 · Tiempo de vida y renovación
| Token | Duración | Estado |
|---|---|---|
| Access Token | 8 horas por defecto | Disponible y revocable |
| Refresh Token | 7–30 días (por definir) | Planificado (v2) |
Refresh (contrato reservado)
POST /api/v1/auth/refresh
Content-Type: application/json
{
"refresh_token": "<refresh_token>"
}
Estado: Planificado para una versión posterior (v2).
Respuesta prevista: nuevo token + expires_in sin reenviar credenciales.
7 · Códigos de respuesta
| Código | Significado |
|---|---|
| 200 | Login exitoso |
| 400 | Solicitud inválida · username ambiguo sin empresa_slug |
| 401 | Usuario o contraseña incorrectos |
| 403 | Usuario suspendido o sin acceso · sin empresa asignada |
| 429 | Demasiados intentos (5 / 15 min por IP) |
| 500 | Error interno |
Error estándar (auth)
{
"error": {
"code": "LOGIN_FAILED",
"message": "Usuario o contraseña incorrectos"
}
}
Formato completo de errores → MAG-06 · Manejo de errores.
8 · Cierre de sesión
POST /api/v1/auth/logout
Authorization: Bearer <token>
En la versión actual el cliente elimina el token almacenado. En futuras versiones podrá invalidarse mediante lista de revocación.
9 · Buenas prácticas
| # | Regla |
|---|---|
| 1 | Nunca almacenar el JWT en URLs |
| 2 | Utilizar siempre HTTPS en producción |
| 3 | No incluir información confidencial en el payload |
| 4 | Renovar el token al expirar (o vía refresh en MAG v2) |
| 5 | El servidor valida firma y expiración en cada solicitud |
10 · Seguridad
La autenticación no concede permisos por sí sola.
Después de validar el token, Roustix verifica:
- Que el usuario exista
- Que la empresa esté activa
- Que el plan permita el módulo solicitado
- Que el rol tenga permisos para la acción
- Que el recurso pertenezca al mismo tenant
Solo entonces se procesa la petición.
11 · Sesión web vs API
| Modo | Uso |
|---|---|
| JWT Bearer | Usuario humano en clientes API |
| API key Bearer | Servicios, ERP, BI y automatizaciones |
API keys mediante un autenticador unificado sin ampliar el acceso de sesión web.
12 · Filosofía del capítulo
El JWT no solo identifica al usuario. Identifica el contexto completo de operación: empresa, plan, módulos y permisos. Cada solicitud a Roustix ocurre dentro de ese contexto.