Autenticación y roles¶
Dos mecanismos, para públicos distintos¶
Este servicio tiene dos formas de autenticación independientes. No se reemplazan entre sí — sirven a públicos distintos y conviven al mismo tiempo.
| Mecanismo | Para quién | Endpoint de login | Tabla | Restricción de proceso |
|---|---|---|---|---|
clientId / clientSecret | Un sistema externo llamando a la API sin humano de por medio (machine-to-machine) | POST /api/v1/auth/token | clientes_api | Ninguna — accede a cualquier proceso |
username / password | Una persona (rol ADMIN o FIRMANTE) | POST /api/v1/usuarios/login | usuarios | Sí, si es FIRMANTE |
Ambos devuelven el mismo formato de token: un JWT Bearer firmado con HS512, con expiración configurable (1 hora por defecto). Se usa igual en ambos casos, en el header:
La diferencia está en qué endpoints puede llamar cada uno y si hay restricción de proceso — no en el formato del token en sí.
Login de cliente API (machine-to-machine)¶
POST /api/v1/auth/token
Content-Type: application/json
{
"clientId": "saeta-prod-01",
"clientSecret": "7s_vtHa6pHH5OLNk80u9hpRn6xQW3ZJiMblJiPxz4sM"
}
Respuesta 200:
Este mecanismo no tiene restricción de proceso — con un token de cliente API se puede enviar un documento a cualquier idProcesoFirma que exista, sin necesitar que un ADMIN se lo asigne explícitamente. Está pensado para integraciones de sistema a sistema (por ejemplo, un ERP que envía documentos automáticamente).
Login de persona (humano)¶
POST /api/v1/usuarios/login
Content-Type: application/json
{
"username": "sfirmante",
"password": "cambiar123"
}
Respuesta 200: mismo formato que el anterior (accessToken, tokenType, expiresIn). La diferencia es lo que viaja dentro del JWT: el rol de esa persona (ADMIN o FIRMANTE), que determina qué endpoints puede llamar después.
Roles¶
ADMIN — único y global (cliente_id es NULL en la tabla usuarios). Gestiona todo: - Crea clientes (organizaciones). - Crea firmantes — la API nunca permite crear otro ADMIN, solo puede crear usuarios con rol FIRMANTE, por diseño. - Asigna procesos a firmantes. - Puede listar todos los procesos configurados en el sistema, para saber qué id asignarle a cada firmante.
FIRMANTE — pertenece a un cliente específico. Solo puede: - Ver sus propios procesos asignados (GET /api/v1/mis-procesos), con el certificado correspondiente a cada uno. - Enviar, consultar y descargar documentos — pero solo contra los procesos que el ADMIN le asignó explícitamente. Si intenta usar un idProcesoFirma que no le pertenece, recibe 403 PROCESO_NO_AUTORIZADO.
Autorización por endpoint¶
| Endpoint | Rol requerido |
|---|---|
POST /api/v1/auth/token | Público |
POST /api/v1/usuarios/login | Público |
POST /api/v1/clientes | ADMIN |
GET /api/v1/clientes | ADMIN |
POST /api/v1/usuarios | ADMIN |
GET /api/v1/usuarios | ADMIN |
POST /api/v1/usuarios/{id}/procesos | ADMIN |
GET /api/v1/procesos | ADMIN |
GET /api/v1/mis-procesos | FIRMANTE |
POST /api/v1/documentos | Cualquiera autenticado* |
GET /api/v1/documentos/{trackingId} | Cualquiera autenticado* |
GET /api/v1/documentos/{trackingId}/archivo | Cualquiera autenticado* |
* Los endpoints de documentos no exigen un rol específico — cualquier token válido (cliente API o usuario) puede llamarlos. La restricción real ahí es distinta: si el token es de un FIRMANTE, se verifica además que el proceso pedido esté en su lista de procesos asignados. Un cliente API o un ADMIN no tienen esa restricción.
Cómo se diferencian los errores de autenticación/autorización¶
| Situación | HTTP | Código |
|---|---|---|
| Sin token, token expirado o mal formado | 401 | TOKEN_INVALIDO |
| Token válido, pero el rol no alcanza para ese endpoint | 403 | ACCESO_DENEGADO |
| Token de FIRMANTE válido, pero pide un proceso que no le asignaron | 403 | PROCESO_NO_AUTORIZADO |
| Login con credenciales incorrectas (cualquiera de los dos mecanismos) | 401 | CREDENCIALES_INVALIDAS |
Credenciales de referencia (entorno de producción)¶
Estas son credenciales reales del entorno de producción. Si este repositorio deja de ser privado en algún momento, hay que rotarlas antes.
Cliente API (para probar el flujo machine-to-machine):
Admin único (para el panel/login humano):
Firmante de prueba (pertenece a un cliente, con procesos ya asignados):
Base URL de producción: https://agente.plussigner.com
Cómo se protegen las contraseñas y secretos¶
usuarios.password_hashyclientes_api.client_secret_hashse guardan siempre hasheados con BCrypt — nunca en texto plano, ni siquiera en la base de datos.- El admin único se crea automáticamente al arrancar el servicio por primera vez (
AdminBootstrap), sin secretos hardcodeados en el código: si hay variables de entornoADMIN_USERNAME/ADMIN_PASSWORDconfiguradas, las usa; si no, genera un password aleatorio seguro y lo imprime una única vez en el log de arranque. - No existe ningún endpoint para crear otro admin — la única forma es un
INSERTdirecto en la base de datos.
Cómo agregar más credenciales¶
Otro cliente API (INSERT directo, con el secreto ya hasheado en BCrypt):
INSERT INTO clientes_api (nombre, client_id, client_secret_hash, activo, fecha_creacion)
VALUES ('nombre-del-sistema', 'client-id-nuevo', '<hash-bcrypt>', 1, datetime('now'));
Un firmante nuevo: por la API, no por SQL — POST /api/v1/usuarios (requiere token de ADMIN), con {"nombre", "username", "password", "clienteId"}. Ver el detalle completo en Referencia de API.