Autenticación de APIs: API keys, OAuth2 y JWT — ¿qué es realmente distinto, y cuándo se combinan?
API keys, OAuth2 y JWT se tratan como competidores, pero cada uno responde una pregunta distinta sobre identidad, delegación y forma del token.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
Autenticación de APIs: API keys, OAuth2 y JWT — ¿qué es realmente distinto, y cuándo se combinan?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#Tres capas distintas que se están comparando
Esta pregunta se hace porque los candidatos suelen tratar "API key", "OAuth2" y "JWT" como tres opciones que compiten entre sí, cuando en realidad responden tres preguntas diferentes y no son mutuamente excluyentes:
- Una API key responde "¿qué aplicación me está llamando?" — es una credencial estática que identifica a un cliente, sin ninguna noción inherente de la persona detrás.
- OAuth2 responde "¿cómo delega un usuario a una aplicación de terceros acceso limitado a sus recursos, sin entregarle su contraseña?" — es un marco de delegación y autorización, un conjunto de flujos (grant types) para obtener un token.
- Un JWT responde "¿cómo luce un token autocontenido y verificable?" — es un formato de token (una estructura firmada, codificada en base64url), no un protocolo. Los access tokens de OAuth2 suelen ser JWTs, pero no están obligados a serlo.
Mezclar esto en una respuesta de entrevista es el error más común: decir "usamos JWT en lugar de OAuth2" no termina de tener sentido, porque uno es un flujo de trabajo y el otro es una forma de token que ese flujo puede (opcionalmente) producir.
#API keys
Una API key es un secreto largo, estático y opaco que se envía en cada petición, típicamente en un encabezado:
curl https://api.example.com/v1/orders \-H "X-API-Key: sk_live_51Hh2c9K4f9pQeT2xRedacted"
Es barata de implementar y muy adecuada para tráfico servidor-a-servidor, niveles públicos de una API, y medición de uso por cliente — pero tiene debilidades reales: no lleva identidad de usuario, normalmente no expira por sí sola, y revocar una key filtrada requiere una búsqueda y una rotación en lugar de que la key simplemente venza. Trata una API key como identificación de la aplicación, no de la persona que la usa.
#OAuth2
OAuth2 es un marco construido alrededor de cuatro roles — el propietario del recurso (el usuario), el cliente (la app), el servidor de autorización (emite tokens) y el servidor de recursos (la API protegida) — y un puñado de grant types para distintas situaciones. Una integración servidor-a-servidor sin ningún humano en el medio típicamente usa el grant de client credentials:
curl -X POST https://auth.example.com/oauth/token \-H "Content-Type: application/x-www-form-urlencoded" \-d "grant_type=client_credentials" \-d "client_id=partner-integration-42" \-d "client_secret=REDACTED" \-d "scope=orders:read"
{"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...","token_type": "Bearer","expires_in": 3600,"scope": "orders:read"}
Una aplicación de cara al usuario en cambio usa el grant de authorization code (idealmente con PKCE), que produce tanto un access token de vida corta como un refresh token de vida más larga, de modo que la app nunca tiene que almacenar la contraseña del usuario.
#JWT
Un JWT (JSON Web Token) son tres segmentos codificados en base64url — header, payload, firma — separados por puntos. El payload lleva claims:
{"iss": "https://auth.example.com/","sub": "user_9f83a1","aud": "orders-api","scope": "orders:read orders:write","exp": 1755792000,"iat": 1755788400}
Como está firmado (comúnmente con RS256 o HS256), un servidor de recursos puede verificar la autenticidad de un JWT y leer sus claims sin llamar de vuelta al servidor de autorización — ese carácter sin estado es la razón principal por la que los access tokens de OAuth2 se emiten tan a menudo como JWTs:
const jwt = require("jsonwebtoken");function verifyAccessToken(token) {return jwt.verify(token, PUBLIC_KEY, {algorithms: ["RS256"],audience: "orders-api",issuer: "https://auth.example.com/",});}
#Cómo se combinan en la práctica
Una forma común en sistemas reales usa una API key para identificar qué aplicación está llamando, y un JWT emitido por OAuth2 para identificar en nombre de qué usuario actúa esa aplicación — ambos presentes en la misma petición:
X-API-Key: sk_live_51Hh2c9K4f9pQeT2xRedactedAuthorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
function authenticate(req, res, next) {const apiKey = req.header("X-API-Key");const authHeader = req.header("Authorization");if (!apiKey || !KNOWN_CLIENTS.has(apiKey)) {return res.status(401).json({ error: "invalid_client" });}const token = authHeader && authHeader.startsWith("Bearer ")? authHeader.slice(7): null;if (!token) {return res.status(401).json({ error: "missing_token" });}try {req.user = verifyAccessToken(token); // quien: el usuario que actuareq.client = KNOWN_CLIENTS.get(apiKey); // que: la app que llamanext();} catch (err) {return res.status(401).json({ error: "invalid_token" });}}
Esto permite aplicar límites de tasa por aplicación y verificaciones de autorización por usuario de forma independiente, en la misma petición, algo que una sola credencial no podría expresar por sí sola.
| Responde | Formato típico | Expiración | Revocación | |
|---|---|---|---|---|
| API key | ¿Qué app llama? | Cadena estática opaca | Usualmente ninguna | Rotación manual |
| OAuth2 | ¿Cómo delega un usuario su acceso? | Un protocolo/flujo, no un formato | Access token: corta. Refresh token: larga | Revocación del refresh token, TTL corto del access token |
| JWT | ¿Cómo luce el token? | header.payload.firma firmado | Lo que diga el claim exp | Difícil antes de exp salvo con una lista de revocación |