# US-MGN001-004: Recuperacion de Password ## Identificacion | Campo | Valor | |-------|-------| | **ID** | US-MGN001-004 | | **Modulo** | MGN-001 Auth | | **Sprint** | Sprint 2 | | **Prioridad** | P1 - Alta | | **Story Points** | 8 | | **Estado** | Ready | | **Autor** | System | | **Fecha** | 2025-12-05 | --- ## Historia de Usuario **Como** usuario que olvido su contraseña **Quiero** poder recuperar el acceso a mi cuenta mediante un proceso seguro **Para** no quedar bloqueado del sistema sin necesidad de contactar soporte --- ## Descripcion El usuario que olvido su contraseña debe poder solicitar un enlace de recuperacion por email. Este enlace le permitira establecer una nueva contraseña de forma segura, invalidando el acceso anterior. ### Contexto - Los usuarios olvidan contraseñas con frecuencia - El proceso debe ser autoservicio - Debe ser seguro contra ataques de enumeracion de emails --- ## Criterios de Aceptacion ### Escenario 1: Solicitud de recuperacion exitosa ```gherkin Given un usuario registrado con email "user@example.com" When solicita recuperacion de password en POST /api/v1/auth/password/request-reset Then el sistema responde con status 200 And el mensaje es "Si el email esta registrado, recibiras instrucciones" And se genera un token de recuperacion con expiracion de 1 hora And se envia email con enlace de recuperacion And tokens anteriores de ese usuario son invalidados ``` ### Escenario 2: Solicitud para email inexistente (seguridad) ```gherkin Given un email "noexiste@example.com" que NO existe en el sistema When solicita recuperacion de password Then el sistema responde con status 200 And el mensaje es IDENTICO al caso exitoso And NO se revela que el email no existe And NO se envia ningun email ``` ### Escenario 3: Cambio de password exitoso ```gherkin Given un usuario con token de recuperacion valido And el token no ha expirado (<1 hora) And el token no ha sido usado When envia nuevo password cumpliendo requisitos Then el sistema actualiza el password hasheado And invalida el token de recuperacion And cierra TODAS las sesiones activas del usuario And envia email confirmando el cambio And responde con status 200 ``` ### Escenario 4: Token de recuperacion expirado ```gherkin Given un token de recuperacion emitido hace mas de 1 hora When el usuario intenta usarlo Then el sistema responde con status 400 And el mensaje es "Token de recuperacion expirado" ``` ### Escenario 5: Token ya utilizado ```gherkin Given un token de recuperacion que ya fue usado When el usuario intenta usarlo nuevamente Then el sistema responde con status 400 And el mensaje es "Token de recuperacion ya utilizado" ``` ### Escenario 6: Password no cumple requisitos ```gherkin Given un token de recuperacion valido When el usuario envia un password que no cumple requisitos | Escenario | Password | Error | | Muy corto | "abc123" | "Password debe tener minimo 8 caracteres" | | Sin mayuscula | "password123!" | "Debe incluir una mayuscula" | | Sin numero | "Password!!" | "Debe incluir un numero" | | Sin especial | "Password123" | "Debe incluir caracter especial" | Then el sistema responde con status 400 And el mensaje indica el requisito faltante And se incrementa el contador de intentos del token ``` ### Escenario 7: Password igual a anterior ```gherkin Given un token de recuperacion valido And el usuario tiene historial de passwords When envia un password igual a uno de los ultimos 5 Then el sistema responde con status 400 And el mensaje es "No puedes usar una contraseña anterior" ``` ### Escenario 8: Validacion de token ```gherkin Given un token de recuperacion When el usuario navega a la pagina de reset con ese token Then el frontend valida el token GET /api/v1/auth/password/validate-token/:token And si es valido muestra el formulario And si no es valido muestra mensaje de error apropiado ``` --- ## Mockup / Wireframe ### Pagina de Solicitud ``` +------------------------------------------------------------------+ | ERP SUITE | +------------------------------------------------------------------+ | | | ╔═══════════════════════════════════╗ | | ║ RECUPERAR CONTRASEÑA ║ | | ╚═══════════════════════════════════╝ | | | | Ingresa tu correo electronico y te enviaremos | | instrucciones para restablecer tu contraseña. | | | | Correo electronico | | +---------------------------+ | | | user@example.com | | | +---------------------------+ | | | | [===== ENVIAR INSTRUCCIONES =====] | | | | ← Volver al login | | | +------------------------------------------------------------------+ ``` ### Confirmacion de Envio ``` +------------------------------------------------------------------+ | ERP SUITE | +------------------------------------------------------------------+ | | | ╔═══════════════════════════════════╗ | | ║ EMAIL ENVIADO ✉️ ║ | | ╚═══════════════════════════════════╝ | | | | Si el email esta registrado, recibiras | | instrucciones en los proximos minutos. | | | | Revisa tu bandeja de entrada y la carpeta | | de spam. | | | | [===== VOLVER AL LOGIN =====] | | | | ¿No recibiste el email? | | Espera 5 minutos y vuelve a intentar. | | | +------------------------------------------------------------------+ ``` ### Pagina de Reset ``` +------------------------------------------------------------------+ | ERP SUITE | +------------------------------------------------------------------+ | | | ╔═══════════════════════════════════╗ | | ║ NUEVA CONTRASEÑA ║ | | ╚═══════════════════════════════════╝ | | | | Nueva contraseña | | +---------------------------+ | | | •••••••••••• | [👁] | | +---------------------------+ | | [████████░░] Fuerte | | | | ✓ Minimo 8 caracteres | | ✓ Al menos una mayuscula | | ✗ Al menos un numero | | ✗ Al menos un caracter especial | | | | Confirmar contraseña | | +---------------------------+ | | | •••••••••••• | [👁] | | +---------------------------+ | | | | [===== CAMBIAR CONTRASEÑA =====] | | | +------------------------------------------------------------------+ ``` ### Token Invalido ``` +------------------------------------------------------------------+ | ERP SUITE | +------------------------------------------------------------------+ | | | ╔═══════════════════════════════════╗ | | ║ ⚠️ ENLACE INVALIDO ║ | | ╚═══════════════════════════════════╝ | | | | El enlace de recuperacion ha expirado | | o ya fue utilizado. | | | | [===== SOLICITAR NUEVO ENLACE =====] | | | +------------------------------------------------------------------+ ``` --- ## Notas Tecnicas ### API ```typescript // 1. Solicitar recuperacion POST /api/v1/auth/password/request-reset { "email": "user@example.com" } // Response 200 { "message": "Si el email esta registrado, recibiras instrucciones" } // 2. Validar token GET /api/v1/auth/password/validate-token/a1b2c3d4e5f6... // Response 200 (valido) { "valid": true, "email": "u***@example.com" } // Response 200 (invalido) { "valid": false, "reason": "expired" | "used" | "invalid" } // 3. Cambiar password POST /api/v1/auth/password/reset { "token": "a1b2c3d4e5f6...", "newPassword": "NewSecurePass123!", "confirmPassword": "NewSecurePass123!" } // Response 200 { "message": "Contraseña actualizada exitosamente" } ``` ### Template de Email ```html Asunto: Recuperacion de contraseña - ERP Suite

Hola {{firstName}},

Recibimos una solicitud para restablecer tu contraseña.

Haz clic en el siguiente enlace para crear una nueva contraseña:

Restablecer Contraseña

Este enlace expira en 1 hora.

Si no solicitaste este cambio, ignora este email. Tu contraseña permanecera sin cambios.

Por seguridad, nunca compartas este enlace con nadie.


IP: {{ipAddress}} | Fecha: {{timestamp}} ``` ### Validaciones de Password ```typescript const PASSWORD_RULES = { minLength: 8, maxLength: 128, requireUppercase: true, requireLowercase: true, requireNumber: true, requireSpecial: true, specialChars: '!@#$%^&*()_+-=[]{}|;:,.<>?', historyCount: 5, // No repetir ultimos 5 }; const PASSWORD_REGEX = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; ``` --- ## Definicion de Done - [ ] Endpoint POST /api/v1/auth/password/request-reset implementado - [ ] Endpoint GET /api/v1/auth/password/validate-token/:token implementado - [ ] Endpoint POST /api/v1/auth/password/reset implementado - [ ] Token de 256 bits generado con crypto.randomBytes - [ ] Token hasheado antes de almacenar - [ ] Email de recuperacion enviado - [ ] Validacion de politica de password - [ ] Historial de passwords implementado - [ ] Logout-all despues de cambio - [ ] Email de confirmacion enviado - [ ] Frontend: ForgotPasswordPage - [ ] Frontend: ResetPasswordPage - [ ] Frontend: Password strength indicator - [ ] Tests unitarios (>80% coverage) - [ ] Tests e2e pasando - [ ] Code review aprobado --- ## Dependencias ### Requiere | Item | Descripcion | |------|-------------| | EmailService | Para enviar emails | | Tabla password_reset_tokens | Almacenar tokens | | Tabla password_history | Historial de passwords | | US-MGN001-002 | Logout-all functionality | ### Bloquea | Item | Descripcion | |------|-------------| | - | No bloquea otras historias | --- ## Estimacion | Tarea | Horas | |-------|-------| | Backend: requestPasswordReset() | 3h | | Backend: validateResetToken() | 2h | | Backend: resetPassword() | 4h | | Backend: Password validation | 2h | | Backend: Email templates | 2h | | Backend: Tests | 3h | | Frontend: ForgotPasswordPage | 3h | | Frontend: ResetPasswordPage | 4h | | Frontend: Password strength | 2h | | Frontend: Tests | 2h | | **Total** | **27h** | --- ## Referencias - [RF-AUTH-005](../../01-requerimientos/RF-auth/RF-AUTH-005.md) - Requerimiento funcional - [ET-auth-backend](../../02-modelado/especificaciones-tecnicas/ET-auth-backend.md) - Spec tecnica --- ## Historial | Version | Fecha | Autor | Cambios | |---------|-------|-------|---------| | 1.0 | 2025-12-05 | System | Creacion inicial |