---
id: "RF-AUTH-002"
title: "Autenticacion por Email"
type: "Requirement"
status: "Done"
priority: "Alta"
module: "auth"
epic: "OQI-001"
version: "1.0"
created_date: "2025-12-05"
updated_date: "2026-01-04"
---

# RF-AUTH-002: Autenticación por Email

**Version:** 1.0.0
**Fecha:** 2025-12-05
**Estado:** ✅ Implementado
**Prioridad:** P0 (Crítica)
**Épica:** [OQI-001](../_MAP.md)

---

## Descripción

El sistema debe permitir a los usuarios registrarse e iniciar sesión mediante email y contraseña, con verificación de email obligatoria y recuperación de contraseña segura.

---

## Objetivo de Negocio

- Proporcionar método de auth tradicional para usuarios que prefieren no usar OAuth
- Mantener control total sobre las credenciales
- Cumplir con requisitos regulatorios de identificación

---

## Requisitos Funcionales

### RF-AUTH-002.1: Registro

**DEBE:**
1. Aceptar email, contraseña, nombre y apellido
2. Validar formato de email (RFC 5322)
3. Validar política de contraseña
4. Verificar que email no exista en el sistema
5. Hashear contraseña con bcrypt (cost 12)
6. Enviar email de verificación
7. Crear usuario con status `pending_verification`

**NO DEBE:**
1. Almacenar contraseña en texto plano
2. Permitir emails duplicados
3. Revelar si email ya existe (seguridad)

### RF-AUTH-002.2: Verificación de Email

**DEBE:**
1. Generar token único de verificación (64 chars)
2. Almacenar token con TTL de 24 horas
3. Enviar link de verificación por email
4. Validar token al hacer click
5. Marcar email como verificado
6. Invalidar token después de uso

### RF-AUTH-002.3: Login

**DEBE:**
1. Aceptar email y contraseña
2. Verificar que el usuario existe
3. Comparar hash de contraseña
4. Verificar que email está verificado
5. Verificar que cuenta no está bloqueada
6. Generar tokens JWT (access + refresh)
7. Registrar sesión en base de datos

### RF-AUTH-002.4: Recuperación de Contraseña

**DEBE:**
1. Aceptar email del usuario
2. Generar token de reset (64 chars)
3. Almacenar token con TTL de 1 hora
4. Enviar link de recuperación por email
5. Validar token al cambiar contraseña
6. Invalidar todas las sesiones activas
7. Invalidar token después de uso

---

## Política de Contraseña

| Criterio | Requisito |
|----------|-----------|
| Longitud mínima | 8 caracteres |
| Longitud máxima | 128 caracteres |
| Mayúsculas | Al menos 1 |
| Minúsculas | Al menos 1 |
| Números | Al menos 1 |
| Especiales | Al menos 1 (!@#$%^&*) |
| No igual a email | Obligatorio |
| No en lista negra | Opcional (común passwords) |

```typescript
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,128}$/;
```

---

## Flujo de Registro

```
Usuario                    Frontend                   Backend                    DB
   │                          │                          │                        │
   │─── Completa form ───────▶│                          │                        │
   │    - email               │                          │                        │
   │    - password            │                          │                        │
   │    - firstName           │                          │                        │
   │    - lastName            │                          │                        │
   │    - acceptTerms         │                          │                        │
   │                          │                          │                        │
   │                          │─── POST /auth/register ─▶│                        │
   │                          │                          │                        │
   │                          │                          │─── Check email ───────▶│
   │                          │                          │◀── Not exists ─────────│
   │                          │                          │                        │
   │                          │                          │─── Hash password ──────│
   │                          │                          │                        │
   │                          │                          │─── INSERT user ───────▶│
   │                          │                          │◀── user created ───────│
   │                          │                          │                        │
   │                          │                          │─── Generate token ─────│
   │                          │                          │─── Store in Redis ─────│
   │                          │                          │─── Send email ─────────│
   │                          │                          │                        │
   │                          │◀── 201 Created ──────────│                        │
   │                          │    { message }           │                        │
   │                          │                          │                        │
   │◀── "Verifica email" ─────│                          │                        │
   │                          │                          │                        │
   │═══ Recibe email ═════════════════════════════════════                        │
   │                          │                          │                        │
   │─── Click link ──────────▶│                          │                        │
   │                          │─── GET /verify-email ───▶│                        │
   │                          │    ?token=xxx            │                        │
   │                          │                          │                        │
   │                          │                          │─── Validate token ─────│
   │                          │                          │─── UPDATE verified ───▶│
   │                          │                          │─── Delete token ───────│
   │                          │                          │                        │
   │                          │◀── 200 OK ───────────────│                        │
   │                          │                          │                        │
   │◀── Redirect to login ────│                          │                        │
```

---

## Flujo de Login

```
Usuario                    Frontend                   Backend                    DB
   │                          │                          │                        │
   │─── Email + Password ────▶│                          │                        │
   │                          │                          │                        │
   │                          │─── POST /auth/login ────▶│                        │
   │                          │                          │                        │
   │                          │                          │─── Find user ─────────▶│
   │                          │                          │◀── user data ──────────│
   │                          │                          │                        │
   │                          │                          │─── Compare hash ───────│
   │                          │                          │                        │
   │                          │                          │─── Check verified ─────│
   │                          │                          │                        │
   │                          │                          │─── Check 2FA ──────────│
   │                          │                          │                        │
   │                          │                          │    [Si 2FA enabled]    │
   │                          │◀── 200 requires_2fa ─────│                        │
   │◀── Show 2FA input ───────│                          │                        │
   │                          │                          │                        │
   │                          │                          │    [Si NO 2FA]         │
   │                          │                          │─── Generate JWT ───────│
   │                          │                          │─── Create session ────▶│
   │                          │                          │                        │
   │                          │◀── 200 OK ───────────────│                        │
   │                          │    { tokens, user }      │                        │
   │                          │                          │                        │
   │◀── Dashboard ────────────│                          │                        │
```

---

## Flujo de Recuperación

```
Usuario                    Frontend                   Backend                    DB
   │                          │                          │                        │
   │─── Email ───────────────▶│                          │                        │
   │                          │                          │                        │
   │                          │─── POST /forgot-password─▶                        │
   │                          │                          │                        │
   │                          │                          │─── Find user ─────────▶│
   │                          │                          │◀── user exists ────────│
   │                          │                          │                        │
   │                          │                          │─── Generate token ─────│
   │                          │                          │─── Store in Redis ─────│
   │                          │                          │─── Send email ─────────│
   │                          │                          │                        │
   │                          │◀── 200 OK ───────────────│                        │
   │                          │    { message }           │                        │
   │                          │                          │                        │
   │◀── "Revisa email" ───────│                          │                        │
   │                          │                          │                        │
   │═══ Recibe email ═════════════════════════════════════                        │
   │                          │                          │                        │
   │─── Click link ──────────▶│                          │                        │
   │                          │─── GET /reset-password ─▶│                        │
   │                          │    ?token=xxx            │                        │
   │                          │                          │                        │
   │◀── Form nueva password ──│                          │                        │
   │                          │                          │                        │
   │─── Nueva password ──────▶│                          │                        │
   │                          │─── POST /reset-password ▶│                        │
   │                          │    { token, password }   │                        │
   │                          │                          │                        │
   │                          │                          │─── Validate token ─────│
   │                          │                          │─── Hash password ──────│
   │                          │                          │─── UPDATE password ───▶│
   │                          │                          │─── Invalidate sessions▶│
   │                          │                          │─── Delete token ───────│
   │                          │                          │                        │
   │                          │◀── 200 OK ───────────────│                        │
   │                          │                          │                        │
   │◀── Redirect to login ────│                          │                        │
```

---

## Templates de Email

### Verificación de Email

```html
Asunto: Verifica tu cuenta de Trading Platform

Hola {{firstName}},

Gracias por registrarte en Trading Platform.

Para completar tu registro, verifica tu email haciendo click aquí:
{{verificationUrl}}

Este link expira en 24 horas.

Si no creaste esta cuenta, ignora este email.

Saludos,
Equipo Trading Platform
```

### Recuperación de Contraseña

```html
Asunto: Recupera tu contraseña de Trading Platform

Hola {{firstName}},

Recibimos una solicitud para restablecer tu contraseña.

Haz click aquí para crear una nueva contraseña:
{{resetUrl}}

Este link expira en 1 hora.

Si no solicitaste este cambio, ignora este email.
Tu contraseña actual seguirá funcionando.

Saludos,
Equipo Trading Platform
```

---

## Manejo de Errores

| Error | Código | Mensaje Usuario |
|-------|--------|-----------------|
| Email existe | 409 | Este email ya está registrado |
| Email no encontrado | 401 | Credenciales inválidas |
| Contraseña incorrecta | 401 | Credenciales inválidas |
| Email no verificado | 403 | Por favor verifica tu email |
| Cuenta bloqueada | 403 | Cuenta bloqueada temporalmente |
| Token inválido | 400 | Link inválido o expirado |
| Token expirado | 400 | Link expirado, solicita uno nuevo |
| Password débil | 400 | La contraseña no cumple requisitos |

**Nota:** No revelar si el email existe en errores de login (seguridad).

---

## Bloqueo por Intentos Fallidos

| Intentos | Acción |
|----------|--------|
| 3 | Warning en UI |
| 5 | Bloqueo 15 minutos |
| 10 | Bloqueo 1 hora |
| 15 | Bloqueo 24 horas |
| 20+ | Requiere contactar soporte |

---

## Seguridad

### Password Hashing

```typescript
import bcrypt from 'bcryptjs';

const SALT_ROUNDS = 12;

async function hashPassword(password: string): Promise<string> {
  return bcrypt.hash(password, SALT_ROUNDS);
}

async function verifyPassword(password: string, hash: string): Promise<boolean> {
  return bcrypt.compare(password, hash);
}
```

### Token Generation

```typescript
import crypto from 'crypto';

function generateSecureToken(): string {
  return crypto.randomBytes(32).toString('hex'); // 64 chars
}
```

---

## Criterios de Aceptación

- [ ] Usuario puede registrarse con email válido
- [ ] Contraseña se valida contra política
- [ ] Email de verificación se envía correctamente
- [ ] Usuario puede verificar email con link
- [ ] Usuario puede hacer login después de verificar
- [ ] Login falla si email no está verificado
- [ ] Usuario puede solicitar recuperación de contraseña
- [ ] Link de recuperación funciona una sola vez
- [ ] Sesiones se invalidan al cambiar contraseña
- [ ] Cuenta se bloquea después de intentos fallidos

---

## Especificación Técnica Relacionada

- [ET-AUTH-002: JWT Tokens](../especificaciones/ET-AUTH-002-jwt.md)

## Historias de Usuario Relacionadas

- [US-AUTH-001: Registro con Email](../historias-usuario/US-AUTH-001-registro-email.md)
- [US-AUTH-002: Login con Email](../historias-usuario/US-AUTH-002-login-email.md)
- [US-AUTH-011: Recuperar Contraseña](../historias-usuario/US-AUTH-011-password-reset.md)
