Backend de autenticacion seguro con TOTP, JWT y auditoria de seguridad en base de datos.
- Listo como base para evolucionar a un sistema de autenticacion de escala mayor.
- Incluye hardening inicial de sesiones, rate limiting y logging de seguridad.
API de autenticacion con segundo factor TOTP, JWT y persistencia en MySQL.
Funciones principales:
- Registro en dos pasos con TOTP.
- Login con password + codigo TOTP.
- Endpoint de perfil autenticado.
- Hash de password con Argon2id (libsodium).
- Cifrado de secreto TOTP con XChaCha20-Poly1305 (libsodium).
- Rate limiting DB-backed para login y enroll start.
- Auditoria de requests y eventos de seguridad en base de datos (IP, user-agent, ruta, resultado).
Espacio para capturas principales:
- Rust (edition 2024)
- Axum + Tokio
- SQLx (MySQL)
- libsodium-rs
- jsonwebtoken
- google-authenticator
- fast_qr
Base URL: http://localhost:3333
- GET /api/health/app
- GET /api/health/crypto
- POST /api/auth/enroll/start
- POST /api/auth/enroll/refresh
- POST /api/auth/enroll/verify
- POST /api/auth/login
- GET /api/auth/me
- POST /api/auth/logout
- Configura variables de entorno en .env.
- Levanta MySQL y confirma DATABASE_URL.
- Ejecuta migraciones automaticas al iniciar con RUN_DB_INIT=true.
- Inicia backend con cargo run.
- Inicia frontend en frontend_example con npm run dev.
- POST /api/auth/enroll/start con name, email, password.
- El backend responde setup_token, qr_base64 y expires_at.
- Si el QR expira, el cliente puede pedir uno nuevo con /api/auth/enroll/refresh usando setup_token.
- El cliente escanea QR y envia current_code a /api/auth/enroll/verify.
- Si valida, se crea usuario final y se emite JWT.
Aclaracion importante:
- El QR no "expira por limitacion tecnica" del formato.
- La expiracion es una medida de seguridad intencional para reducir la ventana de abuso (por ejemplo, clonacion/reuso de un QR filtrado o capturado por terceros).
- Password hashing: Argon2id via libsodium crypto_pwhash.
- Secreto TOTP cifrado en reposo (XChaCha20-Poly1305).
- JWT con validacion de issuer y audience.
- Sesion en cookie HttpOnly + SameSite=Strict (ademas de token en payload para compatibilidad).
- Mensajes de error uniformes en rutas sensibles.
- Bloqueo por intentos fallidos en login y enroll start.
- Logging de seguridad para alta de usuarios, intentos de login, bloqueos y logout.
- Tabla
request_logs: guarda metodo, path, status_code, IP, user-agent y duracion por request. - Tabla
security_events: guarda eventos semanticos de seguridad (login,user_created,enroll_verify, etc.) con outcome y contexto. - Limpieza automatica:
request_logs: retencion de 90 dias.security_events: retencion de 180 dias.
- La migracion del sistema de logs/auditoria es:
migrations/202604040002_audit_logging.sql. - Se aplica automaticamente al iniciar el backend si
RUN_DB_INIT=true|1.
Ultimos eventos de seguridad:
SELECT created_at, event_type, outcome, ip_address, email, route, details
FROM security_events
ORDER BY created_at DESC
LIMIT 100;IPs con mas fallos de login en 24h:
SELECT ip_address, COUNT(*) AS failed_attempts
FROM security_events
WHERE event_type = 'login'
AND outcome IN ('invalid_password', 'invalid_totp', 'rate_limited', 'invalid_input')
AND created_at >= DATE_SUB(UTC_TIMESTAMP(), INTERVAL 1 DAY)
GROUP BY ip_address
ORDER BY failed_attempts DESC
LIMIT 20;Endpoints con mas errores HTTP recientes:
SELECT path, status_code, COUNT(*) AS hits
FROM request_logs
WHERE created_at >= DATE_SUB(UTC_TIMESTAMP(), INTERVAL 1 DAY)
AND status_code >= 400
GROUP BY path, status_code
ORDER BY hits DESC
LIMIT 30;Requeridas:
- DATABASE_URL
- JWT_SECRET
- TOTP_ENC_KEY (base64 de 32 bytes)
- FRONTEND_ORIGIN
Opcionales:
- RUN_DB_INIT=true|1
- QR_MODULE_COLOR (default #000000)
- QR_BACKGROUND_COLOR (default #FFFFFF)
- ENROLL_QR_EXPIRES_SECONDS (default 600, 10 minutos)
- ENROLL_SESSION_MAX_LIFETIME_SECONDS (default 1800, limite absoluto de vida de un setup_token)
- JWT_EXPIRES_SECONDS (default 3600, min 300, max 86400)
- EXPOSE_CRYPTO_HEALTH (default false; oculta /api/health/crypto en produccion)
- AUTH_COOKIE_SECURE (default auto por FRONTEND_ORIGIN https)
- PASSWORD_HASH_PROFILE (interactive|moderate|sensitive, default moderate)
Ejemplo .env:
DATABASE_URL=mysql://user:password@127.0.0.1:3306/auth_api
JWT_SECRET=super_secret_jwt_key_very_long_random_value
TOTP_ENC_KEY=BASE64_DE_32_BYTES
FRONTEND_ORIGIN=http://localhost:5173
RUN_DB_INIT=true
QR_MODULE_COLOR="#F15025"
QR_BACKGROUND_COLOR="#00000000"
ENROLL_QR_EXPIRES_SECONDS=600
ENROLL_SESSION_MAX_LIFETIME_SECONDS=1800
JWT_EXPIRES_SECONDS=3600
EXPOSE_CRYPTO_HEALTH=false
AUTH_COOKIE_SECURE=false
PASSWORD_HASH_PROFILE=moderatePOST /api/auth/enroll/start request:
{
"name": "Juan Perez",
"email": "juan@example.com",
"password": "MiPassword#2026"
}POST /api/auth/enroll/start response:
{
"status": "success",
"data": {
"setup_token": "uuid",
"qr_base64": "...",
"expires_at": "2026-04-04T20:00:00Z"
}
}POST /api/auth/enroll/verify request:
{
"setup_token": "uuid",
"current_code": "123456"
}POST /api/auth/login request:
{
"email": "juan@example.com",
"password": "MiPassword#2026",
"current_code": "123456"
}GET /api/auth/me header:
- Authorization: Bearer (opcional)
Nota de sesion:
- /api/auth/login y /api/auth/enroll/verify emiten cookie HttpOnly llamada auth_token.
- /api/auth/me acepta cookie o bearer.
- /api/auth/logout limpia la cookie.
cargo check
cargo runServidor: http://localhost:3333
Este proyecto esta bajo licencia MIT. Revisa el archivo LICENSE.


