---
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)
