michangarrito/docs/97-adr/ADR-0010-oauth-social.md
rckrdmrd 2c916e75e5 [SIMCO-V4] feat: Agregar documentación SaaS, ADRs e integraciones
Nuevas Épicas (MCH-029 a MCH-033):
- Infraestructura SaaS multi-tenant
- Auth Social (OAuth2)
- Auditoría Empresarial
- Feature Flags
- Onboarding Wizard

Nuevas Integraciones (INT-010 a INT-014):
- Email Providers (SendGrid, Mailgun, SES)
- Storage Cloud (S3, GCS, Azure)
- OAuth Social
- Redis Cache
- Webhooks Outbound

Nuevos ADRs (0004 a 0011):
- Notifications Realtime
- Feature Flags Strategy
- Storage Abstraction
- Webhook Retry Strategy
- Audit Log Retention
- Rate Limiting
- OAuth Social Implementation
- Email Multi-provider

Actualizados:
- MASTER_INVENTORY.yml
- CONTEXT-MAP.yml
- HERENCIA-SIMCO.md
- Mapas de documentación

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 01:43:15 -06:00

259 lines
5.6 KiB
Markdown

---
id: ADR-0010
type: ADR
title: "OAuth Social Strategy"
status: Accepted
decision_date: 2026-01-10
updated_at: 2026-01-10
simco_version: "4.0.1"
stakeholders:
- "Equipo MiChangarrito"
tags:
- oauth
- authentication
- google
- apple
- passport
---
# ADR-0010: OAuth Social Strategy
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | ADR-0010 |
| **Estado** | Accepted |
| **Fecha** | 2026-01-10 |
| **Autor** | Architecture Team |
| **Supersede** | - |
---
## Contexto
MiChangarrito quiere permitir registro e inicio de sesion con cuentas sociales (Google, Apple) para reducir friccion de onboarding. Necesitamos decidir:
1. Que proveedores soportar
2. Como integrar con nuestro sistema de auth existente
3. Como manejar vinculacion de cuentas
---
## Decision
**Implementamos OAuth 2.0 con Passport.js para Google y Apple, con tabla separada oauth_accounts vinculada a users.**
- Google: Principal proveedor social
- Apple: Requerido para iOS App Store
- Passport.js: Strategies bien mantenidas
---
## Alternativas Consideradas
### Opcion 1: Auth0/Firebase Auth
- **Pros:**
- Todo manejado
- Multiples providers
- **Cons:**
- Costo adicional
- Dependencia externa
- Menos control
### Opcion 2: Passport.js (Elegida)
- **Pros:**
- Open source
- Bien documentado
- Control total
- Sin costos adicionales
- **Cons:**
- Mas trabajo de implementacion
- Mantener actualizaciones
### Opcion 3: Implementacion manual
- **Pros:**
- Control absoluto
- **Cons:**
- Mucho trabajo
- Propenso a errores de seguridad
- Mantener cambios de API
---
## Consecuencias
### Positivas
1. **Control:** Logica de negocio en nuestro codigo
2. **Flexibilidad:** Agregar providers facilmente
3. **Integracion:** Se integra con nuestro JWT flow
4. **Costo:** Sin gastos adicionales
### Negativas
1. **Mantenimiento:** Actualizar strategies
2. **Configuracion:** Setup en consolas de providers
---
## Implementacion
### Modelo de Datos
```sql
CREATE TABLE auth.oauth_accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id) NOT NULL,
provider VARCHAR(20) NOT NULL, -- google, apple
provider_user_id VARCHAR(255) NOT NULL,
email VARCHAR(255),
name VARCHAR(255),
avatar_url TEXT,
access_token TEXT,
refresh_token TEXT,
expires_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(provider, provider_user_id)
);
```
### Flujo de Autenticacion
```
1. Usuario hace clic en "Continuar con Google"
2. Redirect a Google OAuth
3. Usuario autoriza
4. Callback a nuestro servidor con code
5. Intercambiar code por tokens
6. Obtener perfil de usuario
7. Buscar/crear usuario en nuestra BD
8. Generar JWT nuestro
9. Redirect a frontend con JWT
```
### Casos de Vinculacion
| Escenario | Accion |
|-----------|--------|
| Nuevo usuario, nuevo email | Crear user + oauth_account |
| Email existe, mismo provider | Error (ya vinculado) |
| Email existe, otro provider | Ofrecer vincular cuentas |
| Usuario logueado vincula nueva | Agregar oauth_account |
### Codigo de Vinculacion
```typescript
async findOrCreateFromOAuth(profile: OAuthProfile): Promise<User> {
// 1. Buscar oauth_account existente
const existingOAuth = await this.oauthRepo.findOne({
where: {
provider: profile.provider,
providerUserId: profile.id,
},
});
if (existingOAuth) {
return existingOAuth.user;
}
// 2. Buscar user por email
const existingUser = await this.userRepo.findOne({
where: { email: profile.email },
});
if (existingUser) {
// Vincular automaticamente si email verificado en provider
if (profile.emailVerified) {
await this.createOAuthAccount(existingUser, profile);
return existingUser;
}
// Sino, pedir confirmacion
throw new EmailExistsError(profile.email, profile.provider);
}
// 3. Crear nuevo usuario
const user = await this.createUser({
email: profile.email,
name: profile.name,
avatarUrl: profile.avatar,
emailVerified: profile.emailVerified,
});
await this.createOAuthAccount(user, profile);
return user;
}
```
---
## Providers Soportados
### Google
```typescript
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback',
scope: ['profile', 'email'],
}, verify));
```
### Apple
```typescript
passport.use(new AppleStrategy({
clientID: process.env.APPLE_CLIENT_ID,
teamID: process.env.APPLE_TEAM_ID,
keyID: process.env.APPLE_KEY_ID,
privateKeyString: process.env.APPLE_PRIVATE_KEY,
callbackURL: '/auth/apple/callback',
scope: ['name', 'email'],
}, verify));
```
---
## Mobile
### Google (Expo)
```typescript
const [request, response, promptAsync] = Google.useAuthRequest({
clientId: GOOGLE_CLIENT_ID,
iosClientId: GOOGLE_IOS_CLIENT_ID,
androidClientId: GOOGLE_ANDROID_CLIENT_ID,
});
```
### Apple (iOS)
```typescript
import * as AppleAuthentication from 'expo-apple-authentication';
const credential = await AppleAuthentication.signInAsync({
requestedScopes: [
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
AppleAuthentication.AppleAuthenticationScope.EMAIL,
],
});
```
---
## Referencias
- [Passport.js](http://www.passportjs.org/)
- [Google Identity](https://developers.google.com/identity)
- [Sign in with Apple](https://developer.apple.com/sign-in-with-apple/)
- [INT-012: OAuth Social](../02-integraciones/INT-012-oauth-social.md)
- [MCH-030: Auth Social](../01-epicas/MCH-030-auth-social.md)
---
**Fecha decision:** 2026-01-10
**Autores:** Architecture Team