Módulo 4 · Autenticación y seguridad

Lección 19 — OAuth2 y OpenID Connect

Flujos, scopes y por qué «conectar con Google» es más difícil de lo que parece.

Publicada
En esta lección
  1. Ejercicio 1 — El flujo
  2. Ejercicio 2 — El id_token
  3. Ejercicio 3 — Linking
  4. Ejercicio 4 — Scopes
  5. Ejercicio 5 — ADR-0009 (esqueleto)
  6. Resumen del profesor

Ejercicio 1 — El flujo

1-2. En tu tráfico: /authorize con response_type=code, code_challenge (S256), state aleatorio; redirect con ?code=...&state=...; canje (POST con code_verifier). Todo lo de la lección, pero tuyo.

  1. state alterado → error de allauth (denegado): evita CSRF del flujo (que el callback de un login iniciado por OTRO usuario se te inyecte).

Ejercicio 2 — El id_token

  1. Claims estándar OIDC: iss (https://accounts.google.com), aud (tu client_id), sub (id estable del usuario), email, email_verified, exp, iat, nonce (si lo pediste), name/picture.
  2. El header JWT lleva kid; el JWKS de Google tiene varias claves públicas rotadas; seleccionas por kid y verificas RS256. Cachear JWKS (con refresh por kid desconocido) es obligatorio: no consultes JWKS en cada login.
  3. Checks mínimos: iss correcto (evita tokens de otro tenant/proveedor), aud = tu client_id (evita reuso de tokens emitidos a otra app), exp/iat vigentes (evita replay de tokens viejos), nonce si lo enviaste (evita replay del mismo código/token inyectado), y email_verified para linking (evita toma de cuentas).

Ejercicio 3 — Linking

  1. A (ambos verificados): enlazar — mismo humano, una cuenta. Al usuario local le añades el social account; no creas duplicado (duplicar rompe su historial de compras).
  2. B: NUNCA enlazar sin email_verified. Crea cuenta aparte o rechaza con mensaje de verificación. El ataque sin esta regla: registro en un proveedor laxo con el email de víctima → tomas su cuenta en tu sistema.
  3. C: dos cuentas locales (identidades distintas hasta prueba de dueño). Unificación: flujo manual autenticado ("estas cuentas son tuyas" con prueba por ambos proveedores) o soporte — automatizar el merge de compras es un problema de integridad (pagos a nombre de quién) que no se improvisa.

Ejercicio 4 — Scopes

  1. has_permission lee request.auth.scope (si emitieras tus tokens con scope) o mapea el cliente (aplicación registrada → scopes concedidos): events:read para listados, tickets:write para reservar, refunds:write solo backoffice/integrador de confianza.
  2. 403 con {"type": ".../missing-scope", "title": "Falta el scope tickets:write", "status": 403}: el integrador sabe qué pedir sin soporte.

Ejercicio 5 — ADR-0009 (esqueleto)

Contexto: el registro con contraseña genera abandono y verificación de email a mano. Decisión: OIDC (Google) con allauth, linking por email verificado, cuenta local siempre. Alternativas descartadas: solo password (fricción), magic links (depende del email igualmente, menos estándar). Consecuencias: JWKS cacheado, nonce/state obligatorios, cuenta local desacopla el uptime del proveedor tras el primer login; el password queda como método alternativo + MFA (20).


Resumen del profesor

  • Authorization Code + PKCE es el único flujo que implementarás en 2026; los roles y el state/nonce son parte del diseño, no del formulario.
  • id_token = identidad (valida y crea tu usuario); access_token = llamar APIs del proveedor. Tu API consume TU identidad emitida tras validar.
  • Linking solo con email verificado; si no, fabricas toma de cuentas.
  • El login social es la puerta; tu sistema emite y gobierna la sesión. El proveedor puede caerse después.

Después: Lección 20 — Hash de contraseñas y MFA.