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. Objetivos
  2. 1. Los cuatro roles y el flujo que usarás
  3. 2. Los tokens que llegan y para qué sirven
  4. 3. Scopes y consentimiento
  5. 4. Implementación honesta en Django
  6. 5. Cuándo NO OAuth
  7. 5. El mapa completo de los flujos OAuth2 (y cuál NO usar jamás)
  8. 6. Scopes de TicketFlow: el diseño que la autorización (21) agradece

Stack: DRF + django-allauth/authlib · Proyecto: TicketFlow Estado: Publicada Prerrequisito: Lección 18 — Sesiones vs tokens


Objetivos

  1. Explicar el flujo Authorization Code + PKCE sin dibujar en la pizarra.
  2. Distinguir los cuatro roles (resource owner, client, auth server, resource server) y los tokens que emite.
  3. Añadir "entrar con Google" a TicketFlow usando OIDC (id_token → usuario local) sin inventar flujos.

1. Los cuatro roles y el flujo que usarás

  • Resource owner: el usuario (dueño de su identidad/cuentas).
  • Client: TicketFlow (tu app pide acceso en su nombre).
  • Authorization server: Google/Auth0/Keycloak (autentica y emite tokens).
  • Resource server: la API que guarda lo protegido (perfil de Google, o tu API).

El flujo moderno (y el único para SPA/móvil): Authorization Code + PKCE:

1. Frontend → Auth server:  /authorize?client_id&redirect_uri&code_challenge&state
2. Usuario inicia sesión en el AUTH SERVER (tú nunca ves su contraseña)
3. Auth server → redirect_uri:  ?code=ABC&state=...
4. Frontend → TU backend:  code + code_verifier
5. Tu backend ↔ Auth server:  intercambia code por tokens (con client_secret + verifier)
6. Tu backend valida id_token (firma JWKS, iss, aud, exp) → usuario local (crea/matching)

PKCE (code_challenge = hash del verifier) evita que un código interceptado sea canjeable (el canje exige el verifier que solo conoce el cliente que lo inició). state enlaza la respuesta con la solicitud (CSRF del flujo OAuth).

2. Los tokens que llegan y para qué sirven

  • id_token (OIDC): JWT con identidad (sub, email, email_verified): es lo que tú VALIDAS para crear tu usuario. No lo uses para llamar APIs.
  • access_token: para llamar al resource server del proveedor (API de Google en nombre del usuario). TicketFlow raramente lo necesita (no lees su calendario): si solo haces login, validas id_token y descartas el resto.
  • refresh_token del proveedor: solo si necesitas llamar su API continuamente.

Errores de entrevista: "el access token de Google lo uso para autenticar en MI API" — no: tu API valida TU sesión/JWT (18) emitido tras validar el id_token. El login social es un mecanismo de autenticación, y tu sistema emite su propia identidad.

3. Scopes y consentimiento

Pides el mínimo: openid email profile para login. Cada scope extra (calendario, contactos) pide confianza y revisión del proveedor. En tu propia API (si TicketFlow ofreciera API a terceros), los scopes serían TU contrato: tickets:read, tickets:write — con el access token local llevando scope y tu autorización (21) comprobándolos.

4. Implementación honesta en Django

django-allauth (o authlib) para el flujo: proveedor Google/OIDC, callback que valida el id_token (JWKS del auth server, aud = tu client_id, iss correcto, exp vigente) y hace account linking (mismo email verificado → misma cuenta local; email no verificado → nunca enlazar, crea cuenta aparte o rechaza). Con el usuario local, emites TU auth (18): sesión o JWT. El proveedor de identidad puede caerse: tu auth sigue (el usuario ya existe localmente; el login social solo es la puerta de entrada).

5. Cuándo NO OAuth

OAuth resuelve "acceder con la identidad de otro". Para un backend interno con 5 usuarios, un login propio + MFA (20) es más simple. Y jamás implementes el flujo a mano con requests: las librerías manejan PKCE, JWKS caching, nonce y estados — reinventarlo es fabricar vulnerabilidades.

5. El mapa completo de los flujos OAuth2 (y cuál NO usar jamás)

OAuth2 define más flujos de los que has oído; el mapa honesto:

FlujoQuiénEstadoUso
Authorization Code + PKCEApp con backend o SPAel estándar actualTicketFlow web, móviles, SPA
Client CredentialsServicio→servicio, sin usuarioválidoEl worker del 29 pidiendo tokens de la pasarela
Device CodeTV, consolas, IoTválido, nichoEl terminal de taquilla física
ImplicitSPA viejaDEPRECATEDNinguno (los tokens iban en el fragmento de URL: filtraban)
Resource Owner PasswordApps de confianza del proveedorDEPRECATEDNinguno (el usuario entrega su contraseña: rompe MFA, 20)

El PKCE (Proof Key for Code Exchange) en tres pasos: el cliente genera un code_verifier aleatorio (43-128 chars), envía su hash code_challenge = S256(verifier) al iniciar, y al canjear el código demuestra el verifier. Sirve para que un código interceptado (app maliciosa en el redirect, log del proxy) sea inútil sin el verifier — obligatorio en flujos de app pública DESDE OAuth 2.1.

6. Scopes de TicketFlow: el diseño que la autorización (21) agradece

El scope es el permiso que el USUARIO concede a la APP (no confundir con los roles del 21, que son permisos del usuario en TU sistema). El diseño de TicketFlow:

openid profile email        ← identidad (OIDC: el id_token y sus claims)
tickets:read                ← leer disponibilidad y eventos (público de todos modos)
tickets:purchase            ← reservar y pagar (el scope que pide el checkout)
organizer:manage_events     ← crear/editar eventos (solo apps del organizador)
organizer:read_sales        ← informes de ventas (el CSV del 31)
offline_access              ← refresh token (la 18): pedirlo EXPLÍCITAMENTE

Las reglas: scopes en plural y por recurso (tickets:purchase, no write); el token de acceso lleva sus scopes y CADA endpoint verifica el suyo (el 403 del 21 cuando el scope no cubre); el front pide el mínimo (principio de minimización del 23); y la pantalla de consentimiento del IdP muestra en lenguaje humano lo que cada scope concede — el usuario decide con información, no con jerga.


  1. ¿Qué problema exacto resuelve PKCE y qué ataque anula en SPA/móvil?
  2. ¿Por qué validas el id_token y no usas el access_token de Google para autenticar en tu API?
  3. Un atacante registra "juan+promo@gmail.com" no verificado y tu sistema enlaza por email: ¿qué recibe? ¿Qué regla lo evita?
  4. ¿Qué comprueba tu backend del id_token además de la firma (mínimo 4 claims)?
  5. ¿Por qué tu login social no depende del uptime del proveedor después del primer login?

Continúa con los ejercicios. Las solutions.md solo tras intentarlo.