--- id: "RF-AUTH-003" title: "Autenticacion por Telefono" 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-003: Autenticación por Teléfono **Version:** 1.0.0 **Fecha:** 2025-12-05 **Estado:** ✅ Implementado **Prioridad:** P1 (Alta) **Épica:** [OQI-001](../_MAP.md) --- ## Descripción El sistema debe permitir a los usuarios autenticarse mediante número de teléfono usando OTP (One-Time Password) enviado por SMS o WhatsApp, facilitando el acceso a usuarios que prefieren no usar email o redes sociales. --- ## Objetivo de Negocio - Ampliar opciones de autenticación para mercado LATAM - Reducir fricción para usuarios móviles - WhatsApp tiene alta penetración en México y LATAM - Proporcionar alternativa sin necesidad de recordar contraseña --- ## Requisitos Funcionales ### RF-AUTH-003.1: Envío de OTP **DEBE:** 1. Aceptar número de teléfono con código de país 2. Validar formato E.164 (+52XXXXXXXXXX) 3. Permitir selección de canal (SMS o WhatsApp) 4. Generar OTP de 6 dígitos 5. Almacenar OTP con TTL de 5 minutos 6. Enviar OTP via Twilio 7. Limitar envíos por número (3 cada 15 min) ### RF-AUTH-003.2: Verificación de OTP **DEBE:** 1. Aceptar número de teléfono y OTP 2. Validar OTP contra almacenado 3. Invalidar OTP después de uso 4. Máximo 3 intentos por OTP 5. Crear o actualizar usuario 6. Generar tokens JWT ### RF-AUTH-003.3: Vinculación de Teléfono **DEBE:** 1. Permitir agregar teléfono a cuenta existente 2. Verificar teléfono con OTP 3. Marcar teléfono como verificado 4. Un teléfono solo puede estar en una cuenta --- ## Canales Soportados | Canal | Proveedor | Costo* | Velocidad | |-------|-----------|--------|-----------| | SMS | Twilio | $0.05 USD | 5-30 seg | | WhatsApp | Twilio | $0.005 USD | 1-5 seg | *Costos aproximados por mensaje en México --- ## Formato de Número ### Validación ```typescript // Formato E.164 const phoneRegex = /^\+[1-9]\d{1,14}$/; // Ejemplos válidos: // +525512345678 (México) // +5491123456789 (Argentina) // +573001234567 (Colombia) ``` ### Normalización ```typescript function normalizePhone(phone: string): string { // Remover espacios, guiones, paréntesis return phone.replace(/[\s\-\(\)]/g, ''); } ``` --- ## Flujo de Autenticación ``` Usuario Frontend Backend Twilio │ │ │ │ │─── Ingresa teléfono ────▶│ │ │ │ +525512345678 │ │ │ │ Selecciona: WhatsApp │ │ │ │ │ │ │ │ │─── POST /auth/phone/send─▶ │ │ │ { phone, channel } │ │ │ │ │ │ │ │ │─── Check rate limit ───│ │ │ │ │ │ │ │─── Generate OTP ───────│ │ │ │ (6 digits) │ │ │ │ │ │ │ │─── Store in Redis ─────│ │ │ │ TTL: 5 min │ │ │ │ │ │ │ │─── Send via Twilio ───▶│ │ │ │ │ │ │ │◀── Message sent ───────│ │ │ │ │ │ │◀── 200 OK ───────────────│ │ │ │ { message, expires } │ │ │ │ │ │ │◀── "Código enviado" ─────│ │ │ │ │ │ │ │═══ Recibe WhatsApp ══════════════════════════════════════════════════════════│ │ "Tu código: 123456" │ │ │ │ │ │ │ │─── Ingresa 123456 ──────▶│ │ │ │ │ │ │ │ │─── POST /auth/phone/verify │ │ │ { phone, code } │ │ │ │ │ │ │ │ │─── Validate OTP ───────│ │ │ │ │ │ │ │─── Find/Create user ───│ │ │ │ │ │ │ │─── Generate JWT ───────│ │ │ │ │ │ │◀── 200 OK ───────────────│ │ │ │ { tokens, user } │ │ │ │ │ │ │◀── Dashboard ────────────│ │ │ ``` --- ## Generación de OTP ```typescript function generateOTP(): string { // 6 dígitos numéricos return Math.floor(100000 + Math.random() * 900000).toString(); } ``` ### Almacenamiento en Redis ```typescript // Key pattern const key = `otp:${phone}`; // Value structure { "code": "123456", "attempts": 0, "channel": "whatsapp", "createdAt": "2025-12-05T10:00:00Z" } // TTL: 5 minutos await redis.setEx(key, 300, JSON.stringify(otpData)); ``` --- ## Mensajes de OTP ### SMS ``` Trading Platform: Tu código de verificación es 123456. Expira en 5 minutos. ``` ### WhatsApp ``` 🔐 *Trading Platform* Tu código de verificación es: *123456* Este código expira en 5 minutos. No compartas este código con nadie. ``` --- ## Rate Limiting ### Por Número de Teléfono | Período | Límite | Acción | |---------|--------|--------| | 15 min | 3 envíos | Bloqueo temporal | | 1 hora | 5 envíos | Bloqueo 1 hora | | 24 horas | 10 envíos | Bloqueo 24 horas | ### Por IP | Período | Límite | Acción | |---------|--------|--------| | 15 min | 10 envíos | Bloqueo temporal | | 1 hora | 20 envíos | Bloqueo 1 hora | --- ## Manejo de Errores | Error | Código | Mensaje Usuario | |-------|--------|-----------------| | Teléfono inválido | 400 | Formato de teléfono inválido | | Rate limit | 429 | Demasiados intentos, espera X minutos | | OTP inválido | 401 | Código incorrecto | | OTP expirado | 401 | Código expirado, solicita uno nuevo | | Twilio error | 502 | Error al enviar mensaje, intenta de nuevo | | Canal no soportado | 400 | Canal de envío no soportado | --- ## Integración Twilio ### Configuración ```env TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx TWILIO_AUTH_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx TWILIO_PHONE_NUMBER=+15555555555 TWILIO_WHATSAPP_NUMBER=+14155238886 ``` ### Envío SMS ```typescript await twilioClient.messages.create({ body: `Trading Platform: Tu código es ${otp}. Expira en 5 min.`, from: process.env.TWILIO_PHONE_NUMBER, to: phone, }); ``` ### Envío WhatsApp ```typescript await twilioClient.messages.create({ body: `🔐 *Trading Platform*\n\nTu código es: *${otp}*\n\nExpira en 5 minutos.`, from: `whatsapp:${process.env.TWILIO_WHATSAPP_NUMBER}`, to: `whatsapp:${phone}`, }); ``` --- ## Reglas de Negocio ### RN-001: Teléfono Existente Si el teléfono ya está registrado: 1. Enviar OTP al número 2. Al verificar, crear sesión con cuenta existente 3. No crear cuenta nueva ### RN-002: Teléfono Nuevo Si el teléfono no está registrado: 1. Crear cuenta nueva con teléfono como identificador 2. Solicitar email posteriormente (opcional) 3. Asignar rol `investor` por defecto ### RN-003: Sin Email Cuentas creadas solo con teléfono: 1. Pueden operar normalmente 2. Se les solicita email para ciertas funciones (inversión real) 3. Pueden agregar email después --- ## Consideraciones de Seguridad ### Prevención de Abuso 1. **Rate limiting agresivo** por número e IP 2. **CAPTCHA** después de 2 intentos fallidos 3. **Bloqueo progresivo** de números sospechosos 4. **Monitoreo** de patrones de abuso ### Protección de Datos 1. **No almacenar** OTPs en logs 2. **Encriptar** números de teléfono en BD 3. **Audit log** de todos los envíos 4. **Eliminar** OTPs después de verificación --- ## Criterios de Aceptación - [ ] Usuario puede solicitar OTP por SMS - [ ] Usuario puede solicitar OTP por WhatsApp - [ ] OTP se recibe en menos de 30 segundos - [ ] OTP expira después de 5 minutos - [ ] Usuario puede verificar OTP correctamente - [ ] Usuario bloqueado después de 3 intentos fallidos - [ ] Rate limiting funciona correctamente - [ ] Usuario existente puede hacer login con teléfono - [ ] Usuario nuevo puede registrarse con teléfono - [ ] Teléfono se puede vincular a cuenta existente --- ## Especificación Técnica Relacionada - [ET-AUTH-004: API Endpoints](../especificaciones/ET-AUTH-004-api.md) ## Historias de Usuario Relacionadas - [US-AUTH-008: Login con SMS](../historias-usuario/US-AUTH-008-phone-sms.md) - [US-AUTH-009: Login con WhatsApp](../historias-usuario/US-AUTH-009-phone-whatsapp.md)