Lección 1 de 415 min
OAuth 2.0 y OpenID Connect
Autenticación frente a autorización, los flujos de OAuth, PKCE, scopes y el ID token de OpenID Connect.
Una app de agenda te ofrece importar los eventos de tu calendario de Google. Hace años, la solución habría sido pedirte la contraseña de Google y guardarla: la app podría leer tu correo, borrar tus fotos y cambiar tu contraseña, y la única forma de quitarle el acceso sería cambiarla tú.
OAuth 2.0 resuelve ese problema: la app recibe un permiso limitado («leer el calendario»), que caduca y que puedes revocar, sin ver nunca tu contraseña. OpenID Connect añade encima la otra mitad, saber quién eres, y es lo que hay detrás de casi todos los botones de «Iniciar sesión con…». En esta lección verás los dos y los flujos que se usan hoy.
Quién eres y qué puedes hacer
Autenticación frente a autorización
Autenticar es comprobar quién eres; autorizar, decidir qué puedes hacer.
La autenticación (authn) responde a «¿quién eres?»: comprobar una contraseña, una huella o un código del móvil. La autorización (authz) responde a «¿qué puedes hacer?»: Ana ha iniciado sesión, pero ¿puede borrar las facturas de otro cliente?
En un aeropuerto, el control del pasaporte te autentica y la tarjeta de embarque te autoriza a subir a un avión concreto. En HTTP se refleja en dos códigos distintos: 401 Unauthorized significa, pese a su nombre, «no sé quién eres», y 403 Forbidden, «sé quién eres, pero no puedes».
Úsalo cuando
Siempre que diseñes un sistema con usuarios: primero decide cómo se autentican y después, por separado, cómo se comprueba cada permiso.
Ten en cuenta
OAuth 2.0 es un protocolo de autorización, no de autenticación: un access token dice qué puede hacer quien lo lleva, no quién es el usuario. Para saber quién es, necesitas OpenID Connect.
GET /facturas/77 (sin token)
→ 401 Unauthorized «¿quién eres?»
GET /facturas/77 (token de Ana, factura de otro cliente)
→ 403 Forbidden «sé que eres Ana, pero esta no es tuya»OAuth 2.0
OAuth 2.0 define cómo una aplicación obtiene un access token para llamar a una API, y lo hace con distintos «flujos» (grant types) según quién pide el token y desde dónde.
Roles y access tokens
Cuatro papeles y un token: el permiso limitado que la app presenta a la API.
- Estándar:
- RFC 6749
- Desde:
- 2012
En OAuth intervienen cuatro roles: el propietario del recurso (tú), el cliente (la app de agenda), el servidor de autorización (el de Google, que te autentica y emite tokens) y el servidor de recursos (la API del calendario). El cliente nunca ve tu contraseña: solo el servidor de autorización la conoce.
El resultado es un access token, una credencial que el cliente envía a la API en la cabecera Authorization: Bearer …. Es un token «al portador»: quien lo tiene, lo usa, así que caduca pronto. Puede ser una cadena opaca que la API consulta al servidor de autorización o un JWT que la API valida por sí misma, como verás en la siguiente lección.
Úsalo cuando
Cuando una aplicación necesita acceder a una API en nombre de un usuario o de sí misma, sin manejar contraseñas ajenas.
Ten en cuenta
Envía los tokens solo por HTTPS y nunca en la URL, donde acaban en logs e historiales. Y no inventes tu propia variante del protocolo: usa una librería certificada o un proveedor.
GET /calendar/v3/users/me/calendarList HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ya29.a0AfH6SMB…Authorization Code con PKCE
El flujo recomendado cuando hay un usuario: también para SPAs y apps móviles.
- PKCE:
- RFC 7636
El cliente redirige al usuario al servidor de autorización, que le pide iniciar sesión y dar su consentimiento. Después lo devuelve a la redirect_uri de la app con un código de un solo uso, y la app canjea ese código por los tokens en el endpoint /token.
PKCE (Proof Key for Code Exchange, se pronuncia «pixi») protege ese canje. Antes de redirigir, la app genera un secreto aleatorio, el code_verifier, y envía solo su hash, el code_challenge. Al canjear el código, presenta el verificador original: alguien que intercepte el código no puede usarlo sin él. Así, una SPA o una app móvil, que no pueden guardar un secreto de cliente, obtienen tokens con seguridad.
El antiguo flujo implícito, que devolvía el token directamente en la URL, está desaconsejado. La revisión OAuth 2.1, que el IETF lleva tiempo preparando, consolida estas buenas prácticas: PKCE para todos los clientes y nada de flujo implícito.
Úsalo cuando
Siempre que un usuario inicie sesión: SPAs en Angular o React, apps móviles, aplicaciones web con backend (que además pueden usar un secreto de cliente).
Ten en cuenta
Usa siempre el parámetro state (o el nonce de OpenID Connect) para asociar la respuesta con la petición que la originó, y registra las redirect_uri exactas en el servidor de autorización, sin comodines.
# 1. El navegador va al servidor de autorización
GET https://auth.ejemplo.com/authorize?response_type=code
&client_id=mi-spa&redirect_uri=https://app.ejemplo.com/callback
&scope=openid%20profile%20pedidos:leer&state=k8Df2x
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
# 2. Vuelve con ?code=… y la app lo canjea junto al verificador
POST https://auth.ejemplo.com/oauth/token
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https://app.ejemplo.com/callback&client_id=mi-spa
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkClient Credentials
Para comunicación entre máquinas: sin usuario, la app pide el token en su nombre.
Cuando no hay ninguna persona delante, como un proceso nocturno que llama a la API de facturación o un microservicio que habla con otro, el cliente se autentica directamente con su client_id y su client_secret (o con un certificado) y recibe un access token.
No hay redirecciones, ni pantalla de consentimiento, ni ID token: el token representa a la aplicación, no a un usuario, y sus permisos se configuran de antemano en el servidor de autorización.
Úsalo cuando
Para backends, tareas programadas y servicios internos que llaman a otras APIs por sí mismos (machine-to-machine).
Ten en cuenta
Solo vale para clientes que pueden guardar un secreto, es decir, servidores. Nunca pongas un client_secret en una SPA o una app móvil: cualquiera puede extraerlo.
POST /oauth/token HTTP/1.1
Host: auth.ejemplo.com
Authorization: Basic Y2llcnJlLW5vY3R1cm5vOnMzY3IzdA==
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&scope=facturas:emitir
→ { "access_token": "eyJhbGciOi…", "token_type": "Bearer", "expires_in": 3600 }Scopes y consentimiento
Los permisos concretos que pide la app y que el usuario acepta o rechaza.
Un scope es una cadena que nombra un permiso: calendar.readonly, pedidos:leer, email. La app los pide en el parámetro scope y el servidor de autorización muestra al usuario una pantalla de consentimiento: «Agenda quiere ver tus calendarios». El token resultante solo incluye los scopes concedidos.
La API, al recibir el token, comprueba que contiene el scope que exige cada operación. Los scopes limitan lo que puede hacer la app; lo que puede hacer el usuario (sus roles y permisos dentro de tu sistema) lo sigue decidiendo tu API.
Úsalo cuando
Al diseñar una API protegida con OAuth: define scopes por tipo de operación y pide en cada app solo los que necesita.
Ten en cuenta
Pide el mínimo y, si hace falta más, pídelo cuando el usuario use esa función (consentimiento incremental). Una app que pide acceso total al correo para mostrar tu nombre genera, con razón, desconfianza.
app.delete("/pedidos/:id", (req, res) => {
const scopes = req.token.scope.split(" ");
if (!scopes.includes("pedidos:borrar")) {
return res.status(403).json({ error: "insufficient_scope" });
}
// …y además, ¿este pedido es del usuario? Eso es autorización tuya
});OpenID Connect
OpenID Connect (OIDC) es una capa sobre OAuth 2.0 que estandariza la autenticación. Usa el mismo flujo Authorization Code con PKCE: basta con añadir el scope openid para recibir, además del access token, un ID token.
OpenID Connect y el ID token
OAuth más identidad: un token firmado que le dice a la app quién ha iniciado sesión.
- Mantiene:
- OpenID Foundation
- Desde:
- 2014
El ID token es un JWT firmado por el proveedor y va dirigido a la app cliente, no a la API. Contiene claims (afirmaciones) estándar: iss (quién lo emite), sub (el identificador único y estable del usuario en ese proveedor), aud (para qué app es), exp e iat (caducidad y emisión) y el nonce que envió la app para evitar reutilizaciones.
Con los scopes estándar profile, email, address y phone llegan claims como name, email, email_verified o picture. Así, «Iniciar sesión con Google» o con Microsoft funcionan igual para cualquier app que hable OIDC.
Úsalo cuando
Siempre que quieras que tus usuarios inicien sesión con un proveedor externo o con tu propio servidor de identidad: es el estándar actual para el login web y móvil.
Ten en cuenta
Identifica al usuario por iss más sub, nunca por el email, que puede cambiar o repetirse entre proveedores. Y no envíes el ID token a tu API como si fuera un access token: para eso está el access token.
{
"iss": "https://accounts.google.com",
"sub": "110169484474386276334",
"aud": "mi-app-agenda.apps.googleusercontent.com",
"exp": 1794045600,
"iat": 1794042000,
"nonce": "n-0S6_WzA2Mj",
"name": "Ana García",
"email": "ana@ejemplo.com",
"email_verified": true
}Userinfo y descubrimiento
Un endpoint para pedir los datos del usuario y un documento que lo describe todo.
El endpoint userinfo devuelve los claims del usuario a quien presente un access token válido con el scope openid. Es útil cuando el ID token llega con lo mínimo o cuando necesitas datos actualizados.
El descubrimiento evita configurar a mano cada URL: todo proveedor OIDC publica un documento JSON en /.well-known/openid-configuration con sus endpoints, los scopes y algoritmos que admite y la dirección de sus claves públicas (jwks_uri). Las librerías solo necesitan la URL del emisor y lo leen todo de ahí.
Úsalo cuando
Al configurar cualquier librería OIDC: dale el emisor (issuer) y deja que descubra el resto. Así, si el proveedor rota sus claves o cambia un endpoint, tu app se adapta sola.
Ten en cuenta
Comprueba que el issuer del documento coincide exactamente con el que esperas y con el iss de los tokens. Una barra final de más es suficiente para que no coincidan.
{
"issuer": "https://auth.ejemplo.com",
"authorization_endpoint": "https://auth.ejemplo.com/authorize",
"token_endpoint": "https://auth.ejemplo.com/oauth/token",
"userinfo_endpoint": "https://auth.ejemplo.com/userinfo",
"jwks_uri": "https://auth.ejemplo.com/.well-known/jwks.json",
"scopes_supported": ["openid", "profile", "email"],
"code_challenge_methods_supported": ["S256"]
}Nota
Resumen de tokens: el access token es para la API y dice qué se puede hacer; el ID token es para la app y dice quién inició sesión. El refresh token, que sirve para pedir tokens nuevos sin volver a iniciar sesión, lo verás en la lección de JWT.
Interactivo
Los flujos de OAuth, cara a cara
Activa o desactiva opciones para compararlas cara a cara.
| Característica | Authorization Code + PKCE | Client Credentials | Implícito |
|---|---|---|---|
| Para quién | SPAs, apps móviles y web con backend | Servidores y tareas programadas | SPAs, antes de que existiera PKCE |
| ¿Hay un usuario? | Sí, inicia sesión y da su consentimiento | No | Sí |
| Cómo llega el token | Se canjea un código de un solo uso en /token | Petición directa a /token | Directamente en la URL de vuelta |
| Secreto de cliente | No hace falta; PKCE lo sustituye | Sí, o un certificado | No |
| Estado actual | El recomendado | El estándar para machine-to-machine | Desaconsejado: el token queda expuesto en la URL |
Ponlo en práctica
Saber qué es cada cosa es la mitad del trabajo. La otra mitad es reconocer cuándo usarla.
Interactivo
¿Qué usarías?
Lee cada situación y elige la opción que mejor la resuelve. Fallar aquí no cuenta: es para practicar.
Cada noche, un proceso de tu backend llama a la API de facturación para emitir las facturas del día. No hay ninguna persona involucrada.
Para recordar
- Autenticar es saber quién es alguien; autorizar, decidir qué puede hacer.
401y403reflejan esa diferencia. - OAuth 2.0 entrega access tokens para llamar a APIs sin compartir contraseñas; OpenID Connect añade el ID token para saber quién inició sesión.
- Con usuario, usa Authorization Code con PKCE, también en SPAs y apps móviles; sin usuario, Client Credentials. El flujo implícito está desaconsejado.
- Los scopes limitan lo que puede hacer la app; lo que puede hacer el usuario lo sigue decidiendo tu API.
- Configura las librerías OIDC con la URL del emisor: el descubrimiento hace el resto.
Comprueba lo aprendido
Cuestionario
Responde las 5 preguntas para completar la lección.
1.¿Qué ataque evita PKCE?
2.¿Cuál es la diferencia entre el ID token y el access token?
3.¿Por qué se desaconseja el flujo implícito?
4.Un servicio obtiene un token con Client Credentials. ¿Qué no recibirá nunca?
5.Ana tiene un token válido con el scope
facturas:leery pide una factura de otro cliente. ¿Qué debería responder la API?