--- id: "RF-AUTH-001" title: "OAuth Multi-proveedor" 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-001: OAuth Multi-proveedor **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 autenticarse mediante proveedores OAuth 2.0 externos, facilitando el registro y login sin necesidad de crear credenciales específicas para la plataforma. --- ## Objetivo de Negocio - Reducir fricción en el registro (aumentar conversión) - Mejorar seguridad delegando auth a proveedores confiables - Obtener datos de perfil verificados automáticamente --- ## Proveedores Requeridos | Proveedor | Prioridad | Mercado Objetivo | |-----------|-----------|------------------| | Google | P0 | Global, mayor adopción | | Facebook | P0 | LATAM, social heavy | | X/Twitter | P1 | Traders, crypto community | | Apple | P1 | Usuarios iOS premium | | GitHub | P2 | Desarrolladores, técnicos | --- ## Requisitos Funcionales ### RF-AUTH-001.1: Flujo OAuth Standard **DEBE:** 1. Generar URL de autorización con parámetros correctos 2. Manejar callback con código de autorización 3. Intercambiar código por access/refresh tokens 4. Obtener información del perfil del usuario 5. Crear o vincular cuenta en el sistema ### RF-AUTH-001.2: Vinculación de Cuentas **DEBE:** 1. Permitir vincular múltiples proveedores a una cuenta 2. Detectar si el email ya existe en el sistema 3. Ofrecer vincular cuentas con mismo email 4. Mantener al menos un método de autenticación activo ### RF-AUTH-001.3: Desvinculación **DEBE:** 1. Permitir desvincular proveedores OAuth 2. Requerir al menos un método de auth activo 3. Confirmar acción antes de desvincular --- ## Datos Requeridos por Proveedor | Campo | Google | Facebook | X/Twitter | Apple | GitHub | |-------|--------|----------|-----------|-------|--------| | provider_user_id | ✅ | ✅ | ✅ | ✅ | ✅ | | email | ✅ | ✅ | ❌* | ✅ | ✅ | | name | ✅ | ✅ | ✅ | ✅ | ✅ | | picture | ✅ | ✅ | ✅ | ❌ | ✅ | | verified_email | ✅ | ✅ | ❌ | ✅ | ✅ | *X/Twitter requiere scope adicional para email --- ## Scopes Requeridos ```yaml google: - profile - email facebook: - email - public_profile twitter: - tweet.read - users.read - offline.access apple: - name - email github: - read:user - user:email ``` --- ## Flujo de Autorización ``` ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ Usuario │ │ Frontend │ │ Backend │ │ Provider │ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │ │ │ │ │ Click "Login │ │ │ │ with Google" │ │ │ │─────────────────▶│ │ │ │ │ │ │ │ │ GET /auth/oauth/ │ │ │ │ google/url │ │ │ │─────────────────▶│ │ │ │ │ │ │ │ │ Generate │ │ │ │ state, nonce │ │ │ │ │ │ │◀─────────────────│ │ │ │ { auth_url } │ │ │ │ │ │ │◀─────────────────│ │ │ │ Redirect to │ │ │ │ auth_url │ │ │ │ │ │ │ │─────────────────────────────────────────────────────▶│ │ │ │ User authorizes │ │ │ │ │ │◀─────────────────────────────────────────────────────│ │ Redirect to │ │ code, state │ │ callback │ │ │ │ │ │ │ │─────────────────▶│ │ │ │ /callback?code= │ │ │ │ │ │ │ │ │ POST /auth/oauth/│ │ │ │ google │ │ │ │ { code, state } │ │ │ │─────────────────▶│ │ │ │ │ │ │ │ │─────────────────▶│ │ │ │ Exchange code │ │ │ │ for tokens │ │ │ │ │ │ │ │◀─────────────────│ │ │ │ access_token, │ │ │ │ user_info │ │ │ │ │ │ │ │ Find/Create user │ │ │ │ Generate JWT │ │ │ │ │ │ │◀─────────────────│ │ │ │ { access_token, │ │ │ │ refresh_token, │ │ │ │ user } │ │ │ │ │ │ │◀─────────────────│ │ │ │ Login success │ │ │ │ │ │ │ ``` --- ## Reglas de Negocio ### RN-001: Email Existente Si el email del proveedor OAuth ya existe en el sistema: 1. Si el usuario está logueado → Vincular proveedor a cuenta existente 2. Si no está logueado → Crear sesión con cuenta existente 3. Registrar el nuevo proveedor OAuth en la cuenta ### RN-002: Cuenta Nueva Si el email no existe: 1. Crear nuevo usuario con datos del proveedor 2. Marcar email como verificado (confiamos en el proveedor) 3. Asignar rol por defecto (`investor`) 4. Generar tokens JWT ### RN-003: Sin Email Si el proveedor no proporciona email (X/Twitter sin scope): 1. Permitir registro/login 2. Solicitar email posteriormente para funciones críticas 3. Marcar cuenta como `email_required` --- ## Manejo de Errores | Error | Código | Mensaje Usuario | |-------|--------|-----------------| | Invalid state | 400 | Sesión expirada, intenta de nuevo | | Code expired | 400 | Autorización expirada, intenta de nuevo | | Provider error | 502 | Error con {provider}, intenta más tarde | | Account suspended | 403 | Cuenta suspendida en {provider} | | Email conflict | 409 | Este email ya está registrado | --- ## Seguridad ### Tokens del Proveedor - Encriptar access_token y refresh_token en DB - No exponer tokens del proveedor al frontend - Usar tokens solo para refresh de datos si es necesario ### State Parameter - Generar state único por solicitud - Almacenar en Redis con TTL de 10 minutos - Validar state en callback - Invalidar state después de uso ### PKCE (Proof Key for Code Exchange) Implementar PKCE para proveedores que lo soporten: - Google ✅ - Apple ✅ - GitHub (no requerido) - Facebook (no requerido) - X/Twitter (OAuth 2.0 con PKCE) ✅ --- ## Configuración Requerida ```env # Google OAuth GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=xxx # Facebook OAuth FACEBOOK_APP_ID=xxx FACEBOOK_APP_SECRET=xxx # X/Twitter OAuth TWITTER_CLIENT_ID=xxx TWITTER_CLIENT_SECRET=xxx # Apple OAuth APPLE_CLIENT_ID=com.trading.auth APPLE_TEAM_ID=xxx APPLE_KEY_ID=xxx APPLE_PRIVATE_KEY=xxx # GitHub OAuth GITHUB_CLIENT_ID=xxx GITHUB_CLIENT_SECRET=xxx # Callback URLs OAUTH_CALLBACK_URL=https://api.trading.com/auth/oauth/callback FRONTEND_URL=https://app.trading.com ``` --- ## Criterios de Aceptación - [ ] Usuario puede iniciar sesión con Google - [ ] Usuario puede iniciar sesión con Facebook - [ ] Usuario puede iniciar sesión con X/Twitter - [ ] Usuario puede iniciar sesión con Apple - [ ] Usuario puede iniciar sesión con GitHub - [ ] Usuario puede vincular múltiples proveedores - [ ] Usuario puede desvincular proveedores (con restricción) - [ ] Emails existentes se detectan correctamente - [ ] State parameter se valida correctamente - [ ] Tokens del proveedor se almacenan encriptados --- ## Especificación Técnica Relacionada - [ET-AUTH-001: OAuth Providers](../especificaciones/ET-AUTH-001-oauth.md) ## Historias de Usuario Relacionadas - [US-AUTH-003: Login con Google](../historias-usuario/US-AUTH-003-oauth-google.md) - [US-AUTH-004: Login con Facebook](../historias-usuario/US-AUTH-004-oauth-facebook.md) - [US-AUTH-005: Login con X/Twitter](../historias-usuario/US-AUTH-005-oauth-twitter.md) - [US-AUTH-006: Login con Apple](../historias-usuario/US-AUTH-006-oauth-apple.md) - [US-AUTH-007: Login con GitHub](../historias-usuario/US-AUTH-007-oauth-github.md)