OAuth 2.0

Autenticación Security Notes Jan 6, 2025 JAVASCRIPT
authentication authorization security tokens delegation

Definicion

¿Alguna vez has hecho clic en “Iniciar sesión con Google” o “Continuar con Facebook” en un sitio web? Eso es OAuth 2.0 en acción. Es el protocolo estándar de la industria que te permite conceder a las aplicaciones acceso limitado a tus cuentas sin compartir tu contraseña. En lugar de confiar en cada app con tus credenciales reales, OAuth te permite autorizar permisos específicos a través del servicio original.

El problema central que OAuth resuelve es este: quieres que una app de terceros acceda a tus datos en otro servicio, pero no quieres darle a esa app tu contraseña. Antes de OAuth, literalmente escribías tu contraseña de Google en algún sitio web aleatorio esperando que no la robaran. OAuth crea un handshake seguro donde te autentificas directamente con Google, apruebas permisos específicos, y la app recibe un token de acceso limitado en lugar de tu contraseña.

OAuth 2.0 define varios “tipos de grant” (flujos) para diferentes situaciones: el flujo de Authorization Code para apps web, Client Credentials para comunicación servidor a servidor, y otros. Cada flujo está diseñado para contextos de seguridad específicos. Por ejemplo, las apps basadas en navegador no pueden guardar secretos, así que usan PKCE (Proof Key for Code Exchange) para agregar seguridad. Entender qué flujo usar y cuándo es crucial para construir integraciones seguras.

Ejemplo

Login social en todas partes: “Iniciar sesión con Google,” “Continuar con Apple,” “Login con GitHub” - todos usan OAuth 2.0. El sitio web nunca ve tu contraseña de Google/Apple/GitHub. Solo recibe prueba de que te autenticaste y obtiene acceso a lo que aprobaste (usualmente solo tu nombre y email).

Conectar apps a tus cuentas: Cuando Zapier pide conectarse a tu Gmail para automatizar flujos de trabajo, OAuth concede a Zapier acceso específico (como leer ciertas etiquetas) sin darle a Zapier tu contraseña de Gmail. Puedes revocar este acceso en cualquier momento desde la configuración de tu cuenta de Google.

Autenticación de apps móviles: Cuando inicias sesión en la app móvil de Spotify, OAuth gestiona la autenticación. La app recibe tokens que le permiten acceder a tus playlists y preferencias. Si te roban el teléfono, puedes revocar esos tokens desde el sitio web de Spotify sin cambiar tu contraseña.

Acceso a API de terceros: Cuando un desarrollador construye una app que usa la API de Twitter para publicar tweets en nombre de usuarios, OAuth asegura que los usuarios autoricen explícitamente ese acceso. Los usuarios pueden ver exactamente qué puede hacer la app y revocar el acceso en cualquier momento.

Analogia

La Llave de Valet del Coche de Lujo: Los coches de lujo tienen llaves de valet que encienden el motor pero no pueden abrir el maletero o la guantera. Cuando le das tu coche a un valet, le das acceso limitado - pueden aparcarlo pero no acceder a tus pertenencias privadas. Los access tokens de OAuth son como llaves de valet para tus cuentas - acceso limitado, específico y revocable.

La Tarjeta Llave del Hotel: Una tarjeta llave de hotel abre tu habitación, quizás el gimnasio y la piscina, pero no las habitaciones de otros huéspedes ni áreas de personal. Y expira cuando haces checkout. Los tokens OAuth funcionan de manera similar - otorgan acceso específico por tiempo limitado, y puedes “hacer checkout” (revocar) en cualquier momento.

El Poder Notarial (Limitado): Podrías dar a alguien poder notarial limitado para manejar asuntos legales específicos en tu nombre - vender esta propiedad específica, firmar este documento específico - sin darles control sobre toda tu vida. OAuth otorga autoridad similarmente limitada a las aplicaciones.

El Pase VIP de Concierto: Un pase VIP te da acceso a áreas específicas - la zona VIP, el backstage - pero no a la cabina de producción o al camerino de la banda. Cada pase tiene permisos específicos. Los scopes de OAuth funcionan como estos niveles de pase, definiendo exactamente qué acceso proporciona cada token.

Code Example


// Flujo OAuth 2.0 Authorization Code (más seguro)

// 1. Redirigir usuario al servidor de autorización
const authUrl = new URL('https://oauth.provider.com/authorize');
authUrl.searchParams.append('response_type', 'code');
authUrl.searchParams.append('client_id', 'your_client_id');
authUrl.searchParams.append('redirect_uri', 'https://yourapp.com/callback');
authUrl.searchParams.append('scope', 'read:user read:email');
authUrl.searchParams.append('state', generateRandomState());
window.location.href = authUrl.toString();

// 2. Manejar callback (lado servidor)
app.get('/callback', async (req, res) => {
  const { code, state } = req.query;

  // Verificar parámetro state (protección CSRF)
  if (state !== req.session.oauthState) {
    return res.status(400).send('State inválido');
  }

  // Intercambiar código por access token
  const tokenResponse = await fetch('https://oauth.provider.com/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: code,
      client_id: 'your_client_id',
      client_secret: process.env.CLIENT_SECRET,
      redirect_uri: 'https://yourapp.com/callback'
    })
  });

  const { access_token, refresh_token } = await tokenResponse.json();

  // Usar access token para llamar APIs
  const userData = await fetch('https://api.provider.com/user', {
    headers: { 'Authorization': `Bearer ${access_token}` }
  });
});

Diagram

sequenceDiagram
participant User
participant App
participant Auth
participant API
User->>App: Petición de login
App->>Auth: Redirigir a /authorize
Auth->>User: Mostrar consentimiento
User->>Auth: Aprobar
Auth->>App: Código de autorización
App->>Auth: Intercambiar por tokens
Auth->>App: Access + Refresh tokens
App->>API: Petición con Bearer token
API->>App: Recurso protegido

Notas de Seguridad

SECURITY NOTES

CRÍTICO - …

Configuración y Validación:

  • Usar Authorization Code Flow con PKCE para SPAs y apps móviles, Client Credentials para servidor a servidor.
  • NUNCA usar Implicit Flow (deprecado en OAuth 2.1).
  • Validar parámetro state para prevenir ataques CSRF.
  • Los client secrets nunca deben exponerse en navegadores o apps móviles.
  • Usar HTTPS para todos los flujos OAuth.
  • Validar redirect_uri con coincidencia exacta (sin wildcards).

Monitoreo y Protección:

  • Implementar almacenamiento apropiado de tokens (cookies httpOnly o almacenamiento seguro).
  • Usar access tokens de corta vida (5-60 min) con rotación de refresh tokens.
  • Validar firmas y claims de tokens.
  • Implementar restricciones de scope siguiendo principio de mínimo privilegio.
  • Monitorear reutilización de códigos de autorización.
  • Proteger contra vulnerabilidades de redirección abierta.
  • Considerar usar OAuth 2.1 para nuevas implementaciones.

Mejores Prácticas

Best Practices
1)Usar Authorization Code Flow con PKCE para todos los clientes públicos (SPAs, móviles).
2)Nunca exponer client_secret en código de navegador o móvil.
3)Siempre validar el parámetro state para prevenir ataques CSRF.
4)Usar coincidencia exacta de redirect_uri (sin wildcards).
5)Implementar rotación de refresh token con tokens de un solo uso.
6)Solicitar solo los scopes mínimos necesarios (mínimo privilegio).

Errores Comunes

Common Mistakes
1) Usar Implicit Flow deprecado para SPAs
2) exponer client secrets en código frontend
3) no validar parámetro state (vulnerabilidad CSRF)
4) usar redirect URIs con wildcards
5) almacenar tokens en localStorage sin protección XSS
6) no implementar rotación de refresh tokens
7) solicitar scopes excesivos
8) confundir OAuth (autorización) con OpenID Connect (autenticación)

Standards & RFCs