--- id: EPIC-MCH-030 type: Epic title: "MCH-030: Auth Social (OAuth 2.0)" code: MCH-030 status: Planificado phase: 7 priority: P1 created_at: 2026-01-10 updated_at: 2026-01-10 simco_version: "4.0.1" dependencies: blocks: [] depends_on: ["MCH-029"] --- # MCH-030: Auth Social (OAuth 2.0) ## Metadata - **Codigo:** MCH-030 - **Fase:** 7 - Expansion - **Prioridad:** P1 - **Estado:** Planificado - **Story Points:** 8 - **Sprint Objetivo:** Sprint 8 ## Descripcion Agregar autenticacion social via OAuth 2.0 con Google y Apple Sign-In para simplificar el onboarding de usuarios. Permite registro e inicio de sesion con un clic, reduciendo friccion y aumentando conversion. ## Objetivos 1. Implementar Login con Google 2. Implementar Sign in with Apple (requerido para iOS) 3. Permitir vinculacion de cuentas sociales a cuenta existente 4. Obtener perfil basico del usuario (nombre, email, foto) ## Alcance ### Incluido - OAuth 2.0 con Google - Sign in with Apple (web + iOS) - Vinculacion de multiples proveedores a una cuenta - Sync de foto de perfil ### Excluido - Facebook Login (baja prioridad) - Microsoft/LinkedIn (B2B futuro) - Two-factor authentication (MCH-002 existente) ## Arquitectura ``` ┌─────────────────────────────────────┐ │ MCH-030: Auth Social │ └─────────────────────────────────────┘ │ ┌─────────────────┴─────────────────┐ ▼ ▼ ┌──────────┐ ┌──────────┐ │ Google │ │ Apple │ │ OAuth │ │ Sign-In │ └────┬─────┘ └────┬─────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────┐ │ Passport.js Strategies │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ oauth_accounts (tabla) │ │ user_id | provider | provider_id │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ auth.users (existente) │ └─────────────────────────────────────────┘ ``` ## Entregables | Entregable | Estado | Sprint | Ubicacion | |------------|--------|--------|-----------| | Google OAuth Strategy | Planificado | 8 | `apps/backend/src/modules/auth/strategies/` | | Apple OAuth Strategy | Planificado | 8 | `apps/backend/src/modules/auth/strategies/` | | Tabla oauth_accounts | Planificado | 8 | `database/schemas/16-oauth.sql` | | Endpoints /auth/google, /auth/apple | Planificado | 8 | `apps/backend/src/modules/auth/` | | UI botones sociales web | Planificado | 8 | `apps/web/src/pages/auth/` | | Implementacion mobile | Planificado | 8 | `apps/mobile/src/screens/auth/` | ## Dependencias ### Depende de - MCH-029 (Email para verificacion de cuenta vinculada) ### Bloquea a - Ninguna --- ## Historias de Usuario ### MCH-US-105: Login con Google **Como** usuario nuevo **Quiero** registrarme/iniciar sesion con mi cuenta de Google **Para** no tener que recordar otra contrasena **Story Points:** 5 **Criterios de Aceptacion:** - [CA-105-1] Boton "Continuar con Google" visible en login y registro - [CA-105-2] Registro automatico si no existe cuenta con ese email - [CA-105-3] Vinculacion automatica si ya existe cuenta con mismo email - [CA-105-4] Obtiene nombre y foto de perfil de Google - [CA-105-5] Funciona en web (popup) y mobile (Expo AuthSession) **Tareas:** | ID | Tarea | Tipo | SP | |----|-------|------|-----| | MCH-TT-105-01 | DDL tabla oauth_accounts | DDL | 0.5 | | MCH-TT-105-02 | Google OAuth strategy (Passport) | Backend | 1 | | MCH-TT-105-03 | Endpoint /auth/google | Backend | 0.5 | | MCH-TT-105-04 | Callback handler /auth/google/callback | Backend | 0.5 | | MCH-TT-105-05 | Servicio de vinculacion de cuentas | Backend | 0.5 | | MCH-TT-105-06 | UI boton Google en web | Frontend | 0.5 | | MCH-TT-105-07 | Implementacion mobile (Expo) | Frontend | 1 | | MCH-TT-105-08 | Tests unitarios e integracion | Test | 0.5 | | MCH-TT-105-09 | Documentacion en INT-012 | Docs | 0 | --- ### MCH-US-106: Login con Apple **Como** usuario de iOS **Quiero** iniciar sesion con Apple ID **Para** usar autenticacion nativa de mi dispositivo **Story Points:** 3 **Criterios de Aceptacion:** - [CA-106-1] Sign in with Apple funcional en iOS nativo - [CA-106-2] Fallback web para Android y Desktop - [CA-106-3] Manejo correcto de email oculto (relay de Apple) - [CA-106-4] Registro automatico con nombre del usuario - [CA-106-5] Cumple requisitos App Store Review Guidelines **Tareas:** | ID | Tarea | Tipo | SP | |----|-------|------|-----| | MCH-TT-106-01 | Apple OAuth strategy | Backend | 0.5 | | MCH-TT-106-02 | Endpoint /auth/apple | Backend | 0.5 | | MCH-TT-106-03 | Manejo de private email relay | Backend | 0.5 | | MCH-TT-106-04 | Implementacion iOS nativa | Frontend | 0.5 | | MCH-TT-106-05 | Fallback web con apple-signin-api | Frontend | 0.5 | | MCH-TT-106-06 | Tests | Test | 0.25 | | MCH-TT-106-07 | Documentacion en INT-012 | Docs | 0.25 | --- ## Resumen de Story Points | Historia | SP | Sprint | |----------|-----|--------| | MCH-US-105: Login con Google | 5 | 8 | | MCH-US-106: Login con Apple | 3 | 8 | | **TOTAL** | **8** | 8 | --- ## Criterios de Aceptacion de Epica - [ ] Login con Google funcional en web y mobile - [ ] Sign in with Apple funcional en iOS - [ ] Cuentas vinculadas correctamente - [ ] No se crean duplicados de usuarios - [ ] Cobertura de tests >80% ## Notas Tecnicas ### Configuracion Google Cloud Console 1. Crear proyecto en Google Cloud Console 2. Habilitar Google+ API 3. Crear OAuth 2.0 Client ID (Web Application) 4. Configurar redirect URIs: - `https://api.michangarrito.com/auth/google/callback` - `http://localhost:3000/auth/google/callback` (dev) ### Configuracion Apple Developer 1. App ID con Sign in with Apple capability 2. Service ID para web 3. Key privada para validar tokens 4. Configurar domains y redirect URLs ### Variables de Entorno ```env # Google OAuth GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=xxx # Apple Sign-In APPLE_CLIENT_ID=com.michangarrito.app APPLE_TEAM_ID=XXXXXXXXXX APPLE_KEY_ID=XXXXXXXXXX APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----..." ``` ## Integraciones Relacionadas - [INT-012: OAuth Social](../02-integraciones/INT-012-oauth-social.md) ## ADRs Relacionados - [ADR-0010: OAuth Social Strategy](../97-adr/ADR-0010-oauth-social.md) --- ## Especificaciones Tecnicas Detalladas (Ref: SAAS-015) ### Proveedores Soportados | Proveedor | Enum Value | Scopes | URL Autorizacion | |-----------|------------|--------|------------------| | Google | `google` | openid email profile | accounts.google.com/o/oauth2/v2/auth | | Apple | `apple` | name email | appleid.apple.com/auth/authorize | ### Modelo de Datos #### Tabla: auth.oauth_connections | Columna | Tipo | Nullable | Descripcion | |---------|------|----------|-------------| | id | uuid | NO | PK, generado automaticamente | | tenant_id | uuid | NO | FK a tenants.tenants(id) | | user_id | uuid | NO | FK a users.users(id) | | provider | auth.oauth_provider | NO | Enum: google, apple | | provider_user_id | varchar(255) | NO | ID unico del usuario en el proveedor | | provider_email | varchar(255) | SI | Email del usuario en el proveedor | | provider_name | varchar(255) | SI | Nombre del usuario en el proveedor | | provider_avatar_url | varchar(500) | SI | URL del avatar del proveedor | | access_token | text | SI | Token de acceso OAuth (encriptado) | | refresh_token | text | SI | Token de refresco OAuth (encriptado) | | token_expires_at | timestamptz | SI | Expiracion del access token | | created_at | timestamptz | NO | Fecha de creacion | | updated_at | timestamptz | NO | Fecha de actualizacion | | last_used_at | timestamptz | SI | Ultimo uso de esta conexion | ### Endpoints API | Metodo | Endpoint | Descripcion | Auth | |--------|----------|-------------|------| | GET | /auth/oauth/:provider/url | Obtener URL de autorizacion | Publica | | POST | /auth/oauth/:provider/callback | Callback OAuth (login/registro) | Publica | | GET | /auth/oauth/connections | Listar conexiones del usuario | JWT | | POST | /auth/oauth/connections/:provider/link | Vincular nuevo proveedor | JWT | | DELETE | /auth/oauth/connections/:provider | Desvincular proveedor | JWT | ### Flujo de Autenticacion OAuth ``` Usuario Frontend Backend Proveedor │ │ │ │ │ Click "Login Google" │ │ │ │───────────────────────>│ │ │ │ │ GET /auth/oauth/google/url │ │ │────────────────────────>│ │ │ │ │ │ │ │ { url, state } │ │ │ │<────────────────────────│ │ │ │ │ │ │ │ Redirect to Google │ │ │<───────────────────────│ │ │ │ │ │ │ │ Autoriza en Google │ │ │ │──────────────────────────────────────────────────────────────────────────>│ │ │ │ │ │ Redirect con code │ │ │ │<──────────────────────────────────────────────────────────────────────────│ │ │ │ │ │ code + state │ │ │ │───────────────────────>│ │ │ │ │ POST /auth/oauth/google/callback │ │ │ { profile, tokens } │ │ │ │────────────────────────>│ Busca/Crea usuario │ │ │ │ Crea conexion OAuth │ │ │ │ Genera JWT │ │ │ { user, accessToken } │ │ │ │<────────────────────────│ │ │ Usuario autenticado │ │ │ │<───────────────────────│ │ │ ``` ### Seguridad 1. **State Parameter**: El state incluye tenant_id, timestamp y random string en base64 para prevenir CSRF 2. **Tokens Encriptados**: Los tokens OAuth se almacenan encriptados en base de datos 3. **RLS Multi-tenant**: Aislamiento completo por tenant usando Row-Level Security 4. **Proteccion de Desvinculacion**: No se permite desvincular el unico metodo de autenticacion 5. **Email Pre-verificado**: Los emails de OAuth se marcan como verificados automaticamente ### Estructura de Archivos Backend ``` apps/backend/src/modules/auth/ ├── controllers/ │ └── oauth.controller.ts ├── services/ │ └── oauth.service.ts ├── entities/ │ ├── oauth-connection.entity.ts │ └── oauth-provider.enum.ts ├── guards/ │ └── jwt-auth.guard.ts └── strategies/ └── jwt.strategy.ts ``` --- ## Referencia Template-SaaS Esta epica esta alineada con el modulo SAAS-015 OAuth de template-saas. | Modulo SAAS | Version | Elementos Integrados | |-------------|---------|---------------------| | SAAS-015 OAuth | 1.0.0 | Endpoints, modelo de datos, flujo OAuth | Ver documentacion fuente en `projects/template-saas/docs/01-modulos/SAAS-015-oauth.md` --- **Ultima actualizacion:** 2026-01-13 **Autor:** Architecture Team **Alineacion:** template-saas v1.0.0