---
id: "US-AUTH-008"
title: "Autenticacion con SMS (Twilio)"
type: "User Story"
status: "To Do"
priority: "Alta"
epic: "OQI-001"
story_points: 5
created_date: "2025-12-05"
updated_date: "2026-01-04"
---

# US-AUTH-008: Autenticación con SMS (Twilio)

**Version:** 1.0.0
**Fecha:** 2025-12-05
**Estado:** Pendiente
**Story Points:** 5
**Prioridad:** P1 (Alta)
**Épica:** [OQI-001](../_MAP.md)

---

## Historia de Usuario

**Como** usuario de Trading Platform
**Quiero** poder registrarme e iniciar sesión usando mi número de teléfono y un código SMS
**Para** tener un acceso rápido sin necesidad de recordar contraseñas

---

## Criterios de Aceptación

### AC-001: Formulario de teléfono

**Dado** que estoy en la página de registro/login
**Cuando** selecciono la opción de teléfono
**Entonces** debería ver:
- Selector de país con banderas (+1, +52, +34, etc.)
- Campo para número de teléfono
- Formato visual según el país seleccionado
- Botón "Enviar código"

### AC-002: Validación de número

**Dado** que ingreso un número de teléfono
**Cuando** el número no es válido para el país seleccionado
**Entonces** debería ver un mensaje de error
**Y** el botón "Enviar código" debería estar deshabilitado

### AC-003: Envío de código SMS

**Dado** que ingresé un número válido
**Cuando** hago click en "Enviar código"
**Entonces** debería:
1. Ver un mensaje "Enviando código..."
2. Recibir un SMS con un código de 6 dígitos
3. Ver pantalla de verificación de código
4. El código debería expirar en 10 minutos

### AC-004: Formato del SMS

**Dado** que solicité un código
**Cuando** recibo el SMS
**Entonces** debería tener el formato:
```
Tu código de Trading Platform es: 123456

Válido por 10 minutos.
No compartas este código.
```

### AC-005: Ingreso de código

**Dado** que recibí el código por SMS
**Cuando** ingreso el código en la app
**Entonces** debería:
- Autoformatear con espacios (123 456)
- Auto-enviar al completar 6 dígitos
- Validar el código en tiempo real

### AC-006: Código correcto - Primer registro

**Dado** que es mi primera vez usando este número
**Cuando** ingreso el código correcto
**Entonces** debería:
1. Ver formulario para completar perfil (nombre, apellido, email opcional)
2. Crear mi cuenta
3. Recibir un JWT token
4. Ser redirigido al dashboard

### AC-007: Código correcto - Login existente

**Dado** que ya tengo una cuenta con este número
**Cuando** ingreso el código correcto
**Entonces** debería:
1. Iniciar sesión automáticamente
2. Recibir un JWT token
3. Ser redirigido al dashboard

### AC-008: Código incorrecto

**Dado** que ingreso un código incorrecto
**Cuando** envío el código
**Entonces** debería:
- Ver mensaje "Código incorrecto"
- Poder intentar nuevamente
- Después de 3 intentos fallidos, invalidar el código
- Poder solicitar un nuevo código

### AC-009: Código expirado

**Dado** que pasaron más de 10 minutos desde el envío
**Cuando** intento usar el código
**Entonces** debería ver mensaje "Código expirado"
**Y** debería poder solicitar un nuevo código

### AC-010: Reenvío de código

**Dado** que no recibí el código o expiró
**Cuando** hago click en "Reenviar código"
**Entonces** debería:
- Esperar 60 segundos antes de permitir reenvío
- Ver contador regresivo "Reenviar en 59s..."
- Recibir un nuevo código (el anterior se invalida)

### AC-011: Rate limiting

**Dado** que solicité 5 códigos en 1 hora
**Cuando** intento solicitar otro
**Entonces** debería ver mensaje:
- "Demasiados intentos. Intenta en 1 hora"

### AC-012: Número ya registrado con email

**Dado** que mi número ya está vinculado a una cuenta de email
**Cuando** completo la verificación SMS
**Entonces** debería iniciar sesión en esa cuenta
**Y** tener ambos métodos de autenticación disponibles

---

## Mockup

```
Paso 1: Ingreso de teléfono
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│          🌟 Ingresa con tu número de teléfono              │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ Número de teléfono                                   │   │
│  │ ┌────────┐ ┌──────────────────────────────────────┐ │   │
│  │ │ 🇺🇸 +1 ▾│ │ (555) 123-4567                       │ │   │
│  │ └────────┘ └──────────────────────────────────────┘ │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │               Enviar código                          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ─────────────────── O continúa con ───────────────────    │
│                                                             │
│  [Email] [Google] [Facebook] [Apple]                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Paso 2: Verificación de código
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│          📱 Ingresa el código que enviamos                 │
│                                                             │
│  Enviamos un código a +1 (555) 123-4567                    │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                      │   │
│  │         ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐        │   │
│  │         │ 1 │ │ 2 │ │ 3 │ │ 4 │ │ 5 │ │ 6 │        │   │
│  │         └───┘ └───┘ └───┘ └───┘ └───┘ └───┘        │   │
│  │                                                      │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ¿No recibiste el código?                                  │
│  Reenviar código (disponible en 58s)                       │
│                                                             │
│  ← Cambiar número                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Paso 3: Completar perfil (solo registro nuevo)
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│          🎉 ¡Bienvenido! Completa tu perfil                │
│                                                             │
│  ┌────────────────────────┐ ┌────────────────────────┐     │
│  │ Nombre                 │ │ Apellido               │     │
│  │ ┌──────────────────┐  │ │ ┌──────────────────┐   │     │
│  │ │ Juan             │  │ │ │ Pérez            │   │     │
│  │ └──────────────────┘  │ │ └──────────────────┘   │     │
│  └────────────────────────┘ └────────────────────────┘     │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ Email (opcional)                                     │   │
│  │ ┌─────────────────────────────────────────────────┐ │   │
│  │ │ juan@email.com                                   │ │   │
│  │ └─────────────────────────────────────────────────┘ │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ☑ Acepto los Términos de Servicio                         │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │               Crear mi cuenta                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

---

## Tareas Técnicas

### Database (DB)

- [ ] Agregar campos a tabla `users`:
  ```sql
  ALTER TABLE users ADD COLUMN phone_number VARCHAR(20) UNIQUE;
  ALTER TABLE users ADD COLUMN phone_verified_at TIMESTAMP;
  ALTER TABLE users ADD COLUMN phone_country_code VARCHAR(5);
  ```
- [ ] Tabla `phone_verification_codes`:
  ```sql
  CREATE TABLE phone_verification_codes (
    id UUID PRIMARY KEY,
    phone_number VARCHAR(20) NOT NULL,
    code VARCHAR(6) NOT NULL,
    attempts INT DEFAULT 0,
    expires_at TIMESTAMP NOT NULL,
    used_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT NOW(),
    INDEX idx_phone_expires (phone_number, expires_at)
  );
  ```
- [ ] Tabla `phone_rate_limits`:
  ```sql
  CREATE TABLE phone_rate_limits (
    id UUID PRIMARY KEY,
    phone_number VARCHAR(20) NOT NULL,
    ip_address VARCHAR(45),
    attempts INT DEFAULT 1,
    window_start TIMESTAMP DEFAULT NOW(),
    created_at TIMESTAMP DEFAULT NOW(),
    INDEX idx_phone_window (phone_number, window_start)
  );
  ```

### Backend (BE)

- [ ] Configurar cuenta de Twilio
- [ ] Obtener Account SID y Auth Token
- [ ] Configurar Twilio Phone Number
- [ ] Endpoint `POST /api/v1/auth/phone/send-code`
  - Validar número con libphonenumber
  - Rate limiting (5 códigos / hora)
  - Generar código aleatorio de 6 dígitos
  - Guardar en DB con expiración
  - Enviar SMS via Twilio
- [ ] Endpoint `POST /api/v1/auth/phone/verify-code`
  - Validar código
  - Verificar no expirado
  - Verificar intentos < 3
  - Crear o actualizar usuario
  - Generar JWT token
- [ ] Endpoint `POST /api/v1/auth/phone/resend-code`
  - Invalidar código anterior
  - Generar nuevo código
  - Verificar cooldown de 60s
- [ ] Service `TwilioSMSService`
  - `sendVerificationCode()`
  - `verifyCode()`
  - `formatPhoneNumber()`
- [ ] Librería: `twilio` SDK
- [ ] Librería: `libphonenumber-js` para validación
- [ ] Tests unitarios (12 casos)
- [ ] Tests de integración con mock de Twilio

### Frontend (FE)

- [ ] Componente `PhoneAuth.tsx`
- [ ] Selector de país con banderas
- [ ] Input de teléfono con formato automático
- [ ] Componente `CodeInput.tsx` (6 dígitos)
- [ ] Componente `CompleteProfile.tsx`
- [ ] Validación con React Hook Form
- [ ] Librería: `react-phone-number-input`
- [ ] Contador regresivo para reenvío
- [ ] Tests con React Testing Library

### Testing (QA)

- [ ] E2E: Registro con teléfono completo
- [ ] E2E: Login con teléfono existente
- [ ] E2E: Código incorrecto (3 intentos)
- [ ] E2E: Código expirado
- [ ] E2E: Reenvío de código
- [ ] E2E: Rate limiting
- [ ] Test de integración con Twilio Test Credentials
- [ ] Test de seguridad: Brute force protection
- [ ] Performance: Envío de SMS < 2s

---

## Dependencias

- **Bloqueantes:**
  - Cuenta de Twilio activa
  - Twilio Phone Number comprado
  - Presupuesto para SMS (aprox $0.0075 USD por SMS)

- **Deseables:**
  - US-AUTH-001: Para vinculación de cuentas

---

## Definition of Ready (DoR)

- [ ] Cuenta de Twilio configurada
- [ ] Twilio Phone Number asignado
- [ ] Presupuesto aprobado para SMS
- [ ] Mockups aprobados
- [ ] API contract definido
- [ ] Estrategia de rate limiting definida

---

## Definition of Done (DoD)

- [ ] Código implementado y revisado
- [ ] Tests unitarios con 80%+ cobertura
- [ ] Tests de integración pasando
- [ ] Tests E2E implementados
- [ ] Twilio configurado en todos los ambientes
- [ ] Rate limiting implementado
- [ ] Logs y monitoring de SMS
- [ ] Costos monitoreados
- [ ] Documentación actualizada
- [ ] QA aprobado en staging
- [ ] Deploy a producción exitoso

---

## Notas Técnicas

### Twilio SMS Flow

1. Usuario ingresa número de teléfono
2. Frontend valida formato
3. Frontend llama `POST /api/v1/auth/phone/send-code`
4. Backend valida número con libphonenumber
5. Backend verifica rate limits
6. Backend genera código aleatorio (6 dígitos)
7. Backend guarda código en DB (expira en 10 min)
8. Backend envía SMS via Twilio API
9. Usuario recibe SMS e ingresa código
10. Frontend llama `POST /api/v1/auth/phone/verify-code`
11. Backend valida código
12. Backend crea/actualiza usuario
13. Backend genera JWT token

### Environment Variables

```env
TWILIO_ACCOUNT_SID=AC...
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_PHONE_NUMBER=+15551234567
TWILIO_VERIFY_SERVICE_SID=VA... # Opcional: usar Twilio Verify
```

### Twilio API Usage

```typescript
import twilio from 'twilio';

const client = twilio(accountSid, authToken);

// Enviar SMS
await client.messages.create({
  body: `Tu código de Trading Platform es: ${code}\n\nVálido por 10 minutos.`,
  from: twilioPhoneNumber,
  to: userPhoneNumber
});
```

### Phone Number Validation

```typescript
import { parsePhoneNumber } from 'libphonenumber-js';

const phoneNumber = parsePhoneNumber(input, countryCode);
if (!phoneNumber || !phoneNumber.isValid()) {
  throw new Error('Invalid phone number');
}
```

### Code Generation

```typescript
// Generar código de 6 dígitos
const code = Math.floor(100000 + Math.random() * 900000).toString();
```

### Rate Limiting Strategy

- 5 códigos por número de teléfono por hora
- 10 códigos por IP por hora
- Cooldown de 60 segundos entre reenvíos
- Máximo 3 intentos de verificación por código

### Security Considerations

- Códigos de 6 dígitos (1 millón de combinaciones)
- Expiración de 10 minutos
- Invalidar después de 3 intentos fallidos
- Rate limiting estricto
- Logs de todos los intentos
- Validación de número en backend
- No devolver información si el número existe o no

### Cost Optimization

- SMS en USA: ~$0.0075 USD
- SMS internacional: $0.0075 - $0.10 USD
- Usar Twilio Verify Service para mejor pricing
- Implementar captcha para prevenir abuso
- Alertas si se excede presupuesto mensual

### Alternative: Twilio Verify Service

En lugar de manejar códigos manualmente, considerar usar Twilio Verify:
- Manejo automático de códigos
- Rate limiting incluido
- Mejor pricing
- Reenvíos automáticos
- Múltiples canales (SMS, Voice, WhatsApp)

---

## Requerimientos Relacionados

- [RF-AUTH-004: Autenticación por Teléfono](../requerimientos/RF-AUTH-004-phone.md)

## Especificaciones Relacionadas

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