RF02: Usuario inicia sesión con correo y contraseña
Descripción
Como usuario registrado, quiero iniciar sesión con mi correo y contraseña para acceder a mis datos financieros de forma segura.
El login verifica las credenciales contra el hash Argon2id almacenado y, si son válidas, crea una nueva sesión ligada al dispositivo emitiendo el par access token (JWT 15 min) + refresh token (opaco 30 días), conforme al Control de Sesiones.
| Campo | Valor |
|---|---|
| Módulo | Auth Module |
| Actor | Usuario registrado |
| Endpoint | POST /auth/login |
| Precondiciones | Existe una cuenta con credenciales de correo/contraseña |
| Prioridad | Alta (MVP) |
| Etapa | MVP |
| Requisitos relacionados | RF01, RF03, RF04, RF11 |
Reglas de negocio
- RN-02.1 — La verificación usa
argon2.verify(hash, password); nunca se compara la contraseña en claro. - RN-02.2 — Un login exitoso crea una sesión nueva. Si se supera el límite del plan (2 gratuito / 5 premium), se revoca automáticamente la sesión más antigua por
last_used_at(ver Control de Sesiones §4.2). - RN-02.3 — Las cuentas creadas solo con login social (sin
password_hash) no pueden usar este flujo; deben usar su proveedor. - RN-02.4 — Login desde un dispositivo nuevo dispara notificación de seguridad (push + email).
- RN-02.5 — Mensaje de error genérico ante credenciales inválidas para no revelar si el correo existe.
Validaciones de entrada
| Campo | Reglas | Mensaje de error |
|---|---|---|
email | Obligatorio. Formato válido. Normalizado a minúsculas. | "Ingresa un correo electrónico válido." |
password | Obligatorio. No vacío. | "Ingresa tu contraseña." |
deviceInfo | Obligatorio (device_name, device_os, device_id). | — (uso interno) |
Las consultas son parametrizadas; no se aceptan inyecciones SQL. Se aplica rate limiting por IP y por cuenta (ver Escenario 4).
Criterios de aceptación
Escenario 1: Login exitoso (happy path)
Dado que tengo una cuenta con correo y contraseña válidos,
Cuando ingreso credenciales correctas,
Entonces el sistema verifica el hash Argon2id,
Y crea una sesión asociada a mi dispositivo,
Y recibo access_token (15 min) y refresh_token (30 días) con 200 OK.
Escenario 2: Credenciales incorrectas
Dado que ingreso un correo inexistente o una contraseña incorrecta,
Cuando intento iniciar sesión,
Entonces el sistema responde 401 Unauthorized,
Y muestra el mensaje genérico "Correo o contraseña incorrectos",
Y no se crea ninguna sesión.
Escenario 3: Cuenta solo-social sin contraseña
Dado que mi cuenta fue creada con Google/Apple y no tiene contraseña,
Cuando intento iniciar sesión con correo y contraseña,
Entonces el sistema responde 401 con el mensaje "Inicia sesión con el método que usaste para registrarte".
Escenario 4: Bloqueo por intentos fallidos (seguridad)
Dado que se registran 5 intentos fallidos en 10 minutos desde la misma IP o cuenta,
Cuando intento nuevamente,
Entonces el sistema bloquea temporalmente (15 min) y responde 429 Too Many Requests,
Y muestra "Demasiados intentos. Intenta de nuevo en unos minutos".
Escenario 5: Login desde dispositivo nuevo
Dado que inicio sesión correctamente desde un dispositivo nunca antes usado, Cuando se crea la sesión, Entonces el sistema envía una notificación push + email indicando dispositivo, OS, hora e IP aproximada.
Escenario 6: Validación de campos y seguridad
Dado que envío campos vacíos, con formato inválido o intentos de inyección SQL,
Cuando el backend procesa la solicitud,
Entonces responde 400 Bad Request por validación,
Y la inyección no se ejecuta gracias a consultas parametrizadas.
Criterios no funcionales
- Respuesta < 1.5 s (incluye verificación Argon2id).
- Comunicación sobre TLS 1.2+.
- El
refresh_tokense guarda enSecureStore; elaccess_tokensolo en memoria. - La contraseña nunca se registra en logs.