Autenticación y Seguridad
Este módulo regula el acceso de usuarios existentes al sistema, garantizando la persistencia de la sesión mediante estándares JWT y la integridad de los datos según el rol.
1. Flujo de Acceso (Miro)
A continuación, se presenta el diagrama de flujo diseñado para el proceso de Login, Recuperación de cuenta.
Instrucciones: Puedes navegar y hacer zoom directamente en el diagrama superior para ver los estados de error y validaciones.
1.1 Resumen textual (fallback sin Miro)
- Login: email + password → valida credenciales → emite cookies HttpOnly (
accessToken,refreshToken) y redirige por rol. - Recuperación: solicita email → envía token temporal (15-30 min) → reset → invalida sesiones previas.
- Social Login: Google Auth → si email existe, une cuentas; si no, crea flujo de onboarding.
- Bloqueo: 5 intentos fallidos → bloqueo temporal/captcha.
1.2 Relación con Registro
- Scope contractual congelado (V1): ver
../04-Marco-Metodologico/32-contratos-registro-autenticacion-v1.md. - Los endpoints
/api/v1/auth/register,/api/v1/auth/token/verify,/api/v1/auth/token/resendestán detallados en el módulo Registro y Onboarding (UX, validaciones, casos de borde). Aquí se listan solo para completitud del servicio de sesión. - Políticas de OTP, rate limits y NFR compartidas aplican a ambos módulos.
POST /api/v1/auth/token/verifyemite sesión inicial por cookiesHttpOnly(accessToken,refreshToken).
1.2 Snapshot (offline)

Ver en pantalla completa
2. Arquitectura de Seguridad
2.1 Gestión de Sesiones (JWT)
El sistema utiliza un esquema de Dual Token:
- Access Token: Emitido en cookie
HttpOnly(accessToken). Caducidad: 15 min. - Refresh Token: Emitido en cookie
HttpOnly(refreshToken). Caducidad: 7 dias.Secure/SameSitedependen de entorno (local:Secure=false,SameSite=Lax;prod:Secure=true,SameSite=Strict).
2.2 Registro de Auditoría
Toda acción de autenticación debe generar un log:
- Intentos fallidos por IP.
- Cambio de contraseña exitoso.
- Vinculación/Desvinculación de cuentas de Google.
3. Métodos de Acceso y Sesión
3.1 Credenciales (Fase 1)
- Identificador: Correo electrónico verificado.
- Seguridad: Uso de JWT (JSON Web Tokens) con tiempo de expiración corto (ej. 1 hora) y Refresh Tokens para mantener la sesión activa sin re-autenticación constante.
3.2 Login Social con Google (V1)
La autenticacion con Google es parte del flujo de la version actual. Se documenta con el patron validado en celeb-be-v1.
3.2.1 Flujo tecnico (Google OAuth 2.0 Authorization Code)
- Front inicia OAuth
- Inicia con Google SDK o URL OAuth (
openid email profile). - Envia
statefirmado conorigin(dominio frontend permitido).
- Inicia con Google SDK o URL OAuth (
- Callback en backend
GET /api/v1/auth/oauth2/google/callback?code=...&state=...- Backend valida
state,originy lista blanca de origins.
- Intercambio y validacion del token de Google
- Backend intercambia
codepor tokens en Google (client_id,client_secret,redirect_uri). - Valida
id_token(issuer/audience/exp/email_verified).
- Backend intercambia
- Resolucion de cuenta local
- Si usuario existe por email: inicia sesion y vincula proveedor si aplica.
- Si no existe: crea cuenta base y deriva a onboarding corto.
- Sesion local
- Siempre se emite sesion local (cookies
accessToken+refreshToken), nunca se reutilizan tokens de Google.
- Siempre se emite sesion local (cookies
3.2.2 Vinculacion de cuenta existente
- Endpoint:
POST /api/v1/auth/oauth2/google/link(requiere sesion activa). - Payload esperado:
id_tokende Google. - Uso: unir cuenta local existente con proveedor Google sin crear nueva cuenta.
3.2.3 Casos de borde / UX
- Cancelacion en Google: mostrar error no bloqueante y permitir login normal.
email_verified=false: rechazar login social y solicitar flujo por correo.stateinvalido ooriginno permitido: rechazar con 401/403.- Correo asociado a otra identidad incompatible: devolver 409 y guiar a recuperacion.
3.2.4 Variables de entorno y seguridad
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETGOOGLE_REDIRECT_URIGOOGLE_ALLOWED_ORIGINS(lista blanca)- Recomendacion: no aceptar callback desde dominios no registrados y auditar
google_auth_success/google_auth_failed.
4. Recuperación de Cuenta
- Flujo: El usuario solicita "Olvidé mi contraseña" -> Recibe un enlace con un token de corta duración (15-30 min) -> Define nueva contraseña.
- Regla de Seguridad: Al cambiar la contraseña, se deben invalidar todas las sesiones activas en otros dispositivos.
5. Detalles Críticos
- Bloqueo por Intentos: Tras 5 intentos fallidos, bloquear el login para esa IP/Correo temporalmente (5 min) o disparar un captcha para prevenir ataques de fuerza bruta.
- Invalidación de Sesión: Al realizar un "Reset Password", todos los tokens activos en otros dispositivos deben ser invalidados.
5.1 Diccionario UX-Técnico por Pantalla
| Pantalla | Elemento UI | ID Técnico (API) | Validación | Mensaje UX en Error |
|---|---|---|---|---|
| Login | Input email | email | Formato email válido | "Revisa tu correo" |
| Login | Input contraseña | password | Mín 8, mayúscula, número | "Contraseña inválida" |
| Login | Botón ingresar | login_submit | Deshabilitar si campos vacíos | "Completa los campos" |
| Login | Checkbox Recuérdame | remember_me | Opcional; extiende refresh | "" |
| Login | Link Recuperar contraseña | forgot_cta | Navega a Forgot | "" |
| Forgot | Input email | email | Email requerido | "Ingresa tu correo para enviarte el enlace" |
| Reset | Input nueva contraseña | new_password | Mín 8, mayúscula, número | "Contraseña débil" |
| Reset | Input confirmar | confirm_password | Debe coincidir | "Las contraseñas no coinciden" |
| Captcha/Bloqueo | Widget captcha | captcha_token | Obligatorio tras bloqueo | "Confirma que no eres un robot" |
| Social Login | Botón Google | google_oauth | Manejar cancelación | "Inicia con Google o usa tu correo" |
6. Lógica de Redirección (Post-Login)
Tras un login exitoso, el sistema debe redirigir según el arreglo roles del perfil de sesión.
| Rol | Destino | Razón UX |
|---|---|---|
| PACIENTE | /home | Acceso directo al buscador de servicios. |
| DOCTOR (Profesional de la Salud) | /doc/dashboard | Gestión operativa inmediata (Citas/Perfil). |
| ENTITY_ADMIN | /entity/dashboard | Gestión operativa inmediata (Citas/Perfiles). |
| CATALOG_ADMIN | /admin/catalogs | Gestión operativa de catálogos maestros. |
| SUPERADMIN | /admin/stats | Panel de control y validación de profesionales. |
- Redirección por Rol:
- Paciente ->
/home - Profesional de Salud ->
/doc/dashboard - Entidad ->
/entity/dashboard - CatalogAdmin ->
/admin/catalogs - SuperAdmin ->
/admin/stats
- Paciente ->
- Manejo de Errores: Diferenciar entre "Usuario no encontrado" y "Contraseña incorrecta" de forma genérica para seguridad ("Credenciales inválidas").
7. Especificaciones Técnicas (Pre-vía Swagger)
Estos endpoints representan el contrato inicial entre Front y Back. En V1, la sesión se transporta con cookies HttpOnly y las respuestas no exponen tokens.
Implementación Backend (Go, DDD + Clean Architecture):
- Handlers en
interfaces/httptraducen DTOs de login/refresh/forgot/reset a use casesLogin,RefreshToken,ForgotPassword,ResetPassword,Logoutenapplication/auth. - Repositorios (
UserRepo,TokenRepo,OtpRepo) son interfaces definidas endomain/application; implementaciones viven eninfrastructure/persistence(Postgres/Redis) yinfrastructure/notifications. - Entidades y lógica de sesión están en
domain; los DTOs expuestos en OpenAPI no dependen de estructuras de persistencia. - Nomenclatura y estructura completas: ver
arquitectura-y-despliegue.md§7.1.
Endpoints de Sesión
Base path: /api/v1
| Recurso | Método | Descripción |
|---|---|---|
/api/v1/auth/login | POST | Valida credenciales, emite cookies de sesión y devuelve perfil (401/422). |
/api/v1/auth/logout | POST | Invalida sesion usando accessToken en cookie (fallback Authorization: Bearer para compatibilidad). |
/api/v1/auth/refresh | POST | Rota sesión usando refreshToken en cookie (401/409). |
/api/v1/auth/forgot-password | POST | Envía email con token temporal (422). |
/api/v1/auth/reset-password | POST | Recibe token y nueva contraseña (400/401/422). |
/api/v1/auth/oauth2/google/callback | GET | Callback OAuth de Google (intercambia code, valida state/origin). |
/api/v1/auth/oauth2/google/link | POST | Vincula Google con cuenta autenticada usando id_token. |
Parámetros exactos de seguridad (AUTH-CTR-004/005)
| Control | Endpoint(s) | Valor exacto |
|---|---|---|
| Access token TTL | /api/v1/auth/login, /api/v1/auth/token/verify, /api/v1/auth/refresh | 900s (15 min) |
| Refresh token TTL | /api/v1/auth/login, /api/v1/auth/token/verify, /api/v1/auth/refresh | 604800s (7 días) en cookie HttpOnly; Secure/SameSite por entorno (local: false/Lax, prod: true/Strict) |
| Rate limit login | /api/v1/auth/login | 10 solicitudes por 300s (5 min) por email+ip |
| Intentos fallidos máximos login | /api/v1/auth/login | 5 intentos; bloqueo 300s (5 min) y captcha al desbloquear |
| Rate limit forgot-password | /api/v1/auth/forgot-password | 3 solicitudes por 900s (15 min) por email+ip |
| Rate limit reset-password | /api/v1/auth/reset-password | 5 solicitudes por 900s (15 min) por email+ip |
| TTL reset token | /api/v1/auth/forgot-password, /api/v1/auth/reset-password | 900s (15 min) |
| OTP TTL compartido con registro | /api/v1/auth/token/verify, /api/v1/auth/token/resend | 900s (15 min) |
| OTP verify intentos/cooldown | /api/v1/auth/token/verify, /api/v1/auth/token/resend | verify: 5 intentos (bloqueo 1800s); resend: cooldown 60s, máximo 3 en 900s |
| Política de refresh reuse | /api/v1/auth/refresh | 409 + REFRESH_REUSE; revocar todos los refresh tokens; invalidar todas las sesiones; forzar re-login; registrar evento REFRESH_REUSE; captcha en siguiente login |
Contrato completo: ver API Swagger en Marco Metodológico o visitar /swagger desde la navbar.
Códigos de error (resumen)
| Endpoint | 400 | 401 | 409 | 422 |
|---|---|---|---|---|
/auth/login | - | Credenciales inválidas | - | Datos inválidos |
/auth/refresh | - | Token expirado/inválido | Reuse detectado | - |
/auth/forgot-password | - | - | - | Email inválido |
/auth/reset-password | Datos faltantes | Token inválido/expirado | - | Contraseña inválida |
Catalogo de errores obligatorio (canonico)
Esta modulo debe responder con el formato y codigos definidos en 11-swagger-ui.md ("Catalogo canonico de errores API").
| Escenario | Codigo canonico | HTTP |
|---|---|---|
| Credenciales invalidas | UNAUTHORIZED | 401 |
| Usuario bloqueado por abuso | RATE_LIMITED | 429 |
| Token refresh reutilizado | CONFLICT | 409 |
| Payload login/reset invalido | VALIDATION_ERROR | 422 |
| Proveedor OAuth no disponible | UPSTREAM_ERROR | 502 |
8. Requerimientos No Funcionales (NFR)
- P95 login < 300ms; refresh < 200ms; reset-password < 400ms.
- Tasa 401/422 < 2% semanal; tasa de reset exitoso > 95%.
- Logs/trazas con
trace_id,user_id,email,ip,route. - Compartidos con Registro: OTP delivery >98% en <30s, P95 verify <350ms.
8.1 SLIs/SLOs y Alertas
| Métrica | SLO | Alerta |
|---|---|---|
login_p95 | < 300ms | Warn > 350ms 5m; Crit > 500ms 5m |
refresh_p95 | < 200ms | Warn > 250ms 5m |
reset_success_rate | > 95% semanal | Crit < 90% |
otp_delivery_success | > 98% en <30s | Warn < 95% o latencia >45s |
rate_limit_blocked | < 0.5% de intentos | Warn > 1% |
8.2 Ejemplos de Requests/Responses
- Login (POST /api/v1/auth/login)
- Request:
{ "email": "user@mail.com", "password": "Secret123" } - Response 200:
{ "user": {"roles": ["PATIENT","DOCTOR"]} } - Response 401:
{ "message": "Credenciales inválidas" }
- Request:
- Refresh (POST /api/v1/auth/refresh)
- Request: sin body (cookie
refreshToken); body opcional solo para compatibilidad legacy. - 409 (reuse):
{ "message": "Refresh token reused" }
- Request: sin body (cookie
- Forgot/Reset
- Request forgot:
{ "email": "user@mail.com" } - Reset 400/422:
{ "message": "Token inválido o expirado" }
- Request forgot:
9. Checklist de Seguridad
- Refresh rotation obligatoria; detectar reuse → invalidar sesión y registrar
REFRESH_REUSE. - Tokens de reset/OTP siempre hash; TTL exactos según tabla "Parámetros exactos de seguridad (AUTH-CTR-004/005)".
- Rate limits, cooldowns, intentos máximos y lockouts deben cumplir los valores exactos de la tabla "Parámetros exactos de seguridad (AUTH-CTR-004/005)".
- Cookies de sesion (
accessToken,refreshToken):HttpOnly;Secure/SameSitepor entorno (local:false/Lax,prod:true/Strict); CORS solo dominios oficiales. - MFA opcional para Admin/Profesional de Salud (guardar secreto cifrado en BD).
- Compartidos con Registro: rate limit
/api/v1/auth/token/verify5 req/15min; masking de email/phone en errores; no loggear PII/PHI.
10. Secuencia de Sesión (referencial)
Ejemplo de Respuesta Exitosa (Login)
{
"status": "success",
"data": {
"token": "eyJhbGciOiJIUzI1...",
"user": {
"id": "uuid-123",
"email": "doctor@ejemplo.com",
"roles": ["PATIENT", "DOCTOR"],
"status": "ACTIVE",
"onboarding_completed": true
}
}
}
11. QA / Testing Funcional
- Login: credencial válida/incorrecta; cuenta bloqueada por intentos; captcha tras bloqueo.
- Refresh: token expirado, reuse detectado, cookie ausente, device distinto.
- Forgot/Reset: token expirado, ya usado, contraseña débil, confirmación distinta.
- Social Login: usuario nuevo vs existente con mismo email; revocación de consentimiento.
- Logout: invalida refresh y access; sesión paralela en otro dispositivo.
12. Variables de Entorno (Front)
VITE_API_BASE=https://api.example.com/api/v1(prod)VITE_API_BASE=http://localhost:8080/api/v1(local)VITE_GOOGLE_CLIENT_ID=...VITE_ENABLE_MFA=true|false
13. Accesibilidad (A11y)
- Formularios navegables con teclado; foco visible en inputs y botones primarios.
- Mensajes de error en texto, asociados al campo (
aria-describedby). - Contraste AA en botones/links y estados de error/success.
- Soportar lector de pantalla en captcha y MFA (códigos numéricos).
14. Control de Abuso y Fraude
- Rate limits por IP y por cuenta; lista gris para comportamientos sospechosos.
- Captcha adaptativo tras 3-5 intentos fallidos o patrones anómalos.
- Registro de dispositivo (fingerprint ligero) para alertar cambios drásticos.
- Alertas de login desde nueva IP/ubicación con opción de cerrar todas las sesiones.
14.1 Uso de Captcha / reCAPTCHA
- Cuándo dispararlo:
- Login: a partir del 5o intento fallido por IP/correo o señales de bot (UA anómalo, alta frecuencia).
- Refresh reuse detectado: obligar captcha en el siguiente login.
- Forgot/Reset: tras 3 solicitudes fallidas de reset en 15 min.
- Social Login: si el proveedor devuelve cancelaciones repetidas (posible scripting).
- Cómo validarlo:
- Front obtiene
captcha_token(reCAPTCHA v3 o hCaptcha) y lo envía en el headerX-Captcha-Token. - Backend valida server-to-server contra el proveedor y rechaza si score < 0.5 o si está ausente cuando es requerido.
- Front obtiene
- UX: mostrar mensaje claro “Completa la verificación para continuar” y permitir reintento sin perder el formulario.
- Observabilidad: loggear
captcha_required=true,captcha_passedyscore(sin exponer el token).
15. Definition of Done (Seguridad)
- Contraseñas hasheadas con Argon2 o BCrypt.
- Headers de seguridad configurados (CORS, Helmet, HSTS).
- No se devuelven datos sensibles (ej. ID de base de datos o contraseñas) en los JSON de respuesta.
- El sistema bloquea el acceso tras X intentos fallidos.
16. Definición y Propósito
Garantizar que usuarios ya registrados obtengan acceso seguro y persistente a su rol (Paciente, Profesional de Salud, Entidad, Admin) mediante credenciales o login social, minimizando riesgo de secuestro de sesión y manteniendo cumplimiento de NFR/seguridad.
17. Actores y Permisos (RBAC)
| Rol | ¿Puede iniciar sesión? | Restricciones / Notas |
|---|---|---|
| Paciente | Sí | Solo scopes de paciente; no acceso a gestión de citas de otros. |
| Profesional de Salud | Sí | Requiere cuenta verificada; puede ver su agenda, reseñas y notificaciones profesionales. |
| Entidad | Sí | Accede a dashboards de sucursal/afiliación; requiere relación aprobada. |
| Admin | Sí | MFA recomendado; acceso a panel de auditoría y validación. |
18. Reglas de Negocio
- Bloqueo temporal tras 5 intentos fallidos; desbloqueo automático o vía captcha.
- Refresh token reuse → invalidar sesión en todos los dispositivos y registrar evento
REFRESH_REUSE. - Reset password invalida todas las sesiones activas.
- Social login (Google): si el correo existe, se vincula; si no, se crea cuenta siguiendo onboarding.
- MFA opcional/obligatorio para Admin y Profesional de Salud según política.
19. Acciones Técnicas y Eventos (Backend)
login_success,login_failed,account_locked,refresh_reuse_detected.forgot_requested,reset_success,reset_failed.social_linked,social_unlinked,mfa_enabled,mfa_challenge_failed. Cada evento debe emitirse a logs contrace_idy a métricas/OTel donde aplique.
20. Casos de Borde y Manejo de Errores
- Usuario inexistente o inactivo → respuesta genérica de credenciales inválidas.
- Cuenta bloqueada por intentos → devolver estado bloqueado y requerir captcha.
- Refresh expirado o reuse → forzar re-login y registrar incidente.
- Token de reset expirado o usado → error 401/422 y opción de reenviar.
- Social login cancelado por el usuario → mostrar mensaje no intrusivo y permitir reintento.
21. Mermaid: Flujo de Navegación
22. Roles, claims y auditoría
- Roles son acumulativos: un access token puede incluir
PATIENT,DOCTORy/oENTITY_ADMIN; el backend valida scopes sin retirar el rol paciente. - Los claims del token deben incluir
sub,email,roles,country_codeylocale(si ya existen en perfil). - Emitir eventos
ROLE_GRANTEDyUSER_PROFILE_UPDATEDconchanged_by, timestamp e IP/UA al otorgar roles o modificar perfil. - PII:
phonedebe cifrarse/mascararse en logs y jamás viajar en texto plano fuera de HTTPS.
23. Criterios de Aceptación por Paso
| Paso | Criterio | Aceptación |
|---|---|---|
| Login | Credenciales válidas devuelven access+refresh y rol | 200 con tokens y perfil |
| Login fallido | Tras 5 intentos se bloquea durante 5 min o se pide captcha | 429 o 423 controlado |
| Refresh | Con refresh válido se entrega nuevo access | 200 y rotation exitosa |
| Forgot/Reset | Token válido permite cambiar contraseña; invalida sesiones previas | 200 y login requerido |
| Social login | Cuenta existente se vincula; nueva crea perfil | 200 con perfil correcto |
24. Fallback de Proveedor de Email
- Primario: proveedor configurado (p.ej. SendGrid); fallback: SES/SMTP.
- Reintentos exponenciales hasta 3 veces; si falla, log crítico y mensaje amigable al usuario.
- Plantillas transaccionales versionadas; no exponer detalles técnicos en la UI.
25. Métricas de Producto (Funnel)
- CTR de acceso al login desde landing/app.
- Conversión login éxito / intentos totales.
- Tasa de recuperación de cuenta exitosa / solicitudes.
- Abandono en captcha o MFA.
- Reuse de refresh detectado por semana.
26. Enlaces y Trazabilidad
- Swagger UI:
/swagger.html(acceso desde/swagger) y contrato YAML en/openapi.yaml. - Doc de Registro y Onboarding:
../05-Producto/registro(flujo y OTP compartidos). - Roadmap técnico:
../04-Marco-Metodologico/roadmap-tecnico(IDs API-01 y UX-01). - Diseños UI: Miro y snapshots en
/miro/auth-login.jpg.