# Cómo implementar autenticación con JWT y OAuth 2.0

**Categoría:** Programación · **Nivel:** Intermedio · **Lectura:** 17 min
**Publicada:** 2026-07-28 · **Actualizada:** 2026-07-28 · **Autoría:** Underc0de
**Versión HTML (canónica):** https://underc0de.org/guias/programacion/autenticacion-con-jwt-y-oauth2/

## Respuesta rápida

**JWT** y **OAuth 2.0** se nombran juntos pero **no son lo mismo**. Un **JWT** (JSON Web Token) es un **formato de token**: un texto compacto y firmado que transporta datos (por ejemplo, quién sos y hasta cuándo vale la sesión), de modo que el servidor puede verificar su autenticidad sin guardar estado. **OAuth 2.0** es un **protocolo de autorización**: define cómo una aplicación obtiene permiso para acceder a recursos en nombre de un usuario, sin manejar su contraseña (es lo que hay detrás de «Iniciar sesión con Google»). A menudo trabajan juntos: OAuth 2.0 *orquesta* el permiso y los tokens que entrega suelen ser *JWT*. Un JWT tiene tres partes separadas por puntos —**cabecera** (algoritmo), **payload** (los datos o *claims*) y **firma** (lo que garantiza que no fue alterado)—; las dos primeras van codificadas en Base64, **no cifradas**, así que nunca deben llevar secretos. El flujo más usado de OAuth 2.0 es **Authorization Code**: la app redirige al usuario al proveedor, este autentica y devuelve un *código*, y la app lo canjea por un **access token** (de vida corta, para llamar a la API) y un **refresh token** (de vida larga, para renovar el anterior sin volver a pedir credenciales). En seguridad, lo esencial: validar **siempre** la firma y la expiración, usar **HTTPS**, no meter datos sensibles en el payload, y expiraciones cortas para el access token.

## JWT y OAuth 2.0 no son lo mismo

El error de partida más común es tratarlos como sinónimos. Son piezas de **niveles distintos** que suelen combinarse:

|  | JWT | OAuth 2.0 |
|---|---|---|
| Qué es | Un formato de token | Un protocolo de autorización |
| Responde a | «¿Cómo transporto y verifico datos de sesión?» | «¿Cómo concedo acceso sin dar la contraseña?» |
| Ejemplo | El texto eyJhbGci… que lleva tu identidad | «Iniciar sesión con Google» |
| Relación | Suele ser el *tipo* de token que OAuth entrega | Orquesta la obtención de esos tokens |

> **La distinción en una frase**
>
> JWT es un **«cómo se ve»** el token; OAuth 2.0 es un **«cómo se consigue»** el permiso. Podés usar JWT sin OAuth (por ejemplo, para tu propia sesión tras un login clásico con usuario y contraseña) y podés usar OAuth con tokens que no sean JWT. Pero en la práctica moderna, lo habitual es **OAuth 2.0 entregando access tokens en formato JWT**. Conviene también nombrar a **OpenID Connect**: es una capa *encima* de OAuth 2.0 que añade autenticación (saber *quién* es el usuario) mediante un *ID token*, ya que OAuth por sí solo trata de autorización, no de identidad.

## Qué es un JWT

Un **JWT** es una cadena con **tres partes** unidas por puntos: cabecera.payload.firma. Las dos primeras van en **Base64** (codificado, *no* cifrado: cualquiera puede leerlas). La tercera es la **firma**, que se calcula con una clave y garantiza que nadie alteró el contenido.

```text
// El payload decodificado de un JWT: datos (claims), nunca secretos
{
  "sub": "1234567890",       // subject: a quién identifica el token
  "name": "Ana Pérez",
  "role": "editor",          // permisos
  "iat": 1722124800,         // issued at: cuándo se emitió
  "exp": 1722128400          // expiration: cuándo caduca (¡validarlo!)
}
```

> **Atención**
>
> Como el payload solo va **codificado**, cualquiera que intercepte el token puede leer su contenido con una herramienta común. Por eso **nunca** debe contener contraseñas, datos de tarjetas ni información sensible. Lo que hace confiable al JWT no es el secreto de sus datos, sino la **firma**: si alguien cambia un solo carácter del payload, la firma deja de coincidir y el servidor rechaza el token. La seguridad está en **verificar la firma y la expiración en cada petición**, no en ocultar el contenido.

## El flujo de OAuth 2.0

El flujo más usado y recomendado es **Authorization Code** (con PKCE para apps públicas). En vez de que la app maneje la contraseña del usuario, se apoya en el **proveedor de identidad**:

1. **Redirección.** La app envía al usuario al proveedor (Google, GitHub…) con lo que pide y a dónde volver.
2. **Autenticación y consentimiento.** El usuario se identifica *en el proveedor* y acepta los permisos. La app nunca ve su contraseña.
3. **Código de autorización.** El proveedor devuelve al usuario a la app con un *código* de un solo uso.
4. **Canje del código.** La app (desde su servidor) canjea ese código por un **access token** y un **refresh token**.
5. **Acceso a la API.** La app usa el *access token* en cada llamada; cuando caduca, usa el *refresh token* para obtener uno nuevo sin molestar al usuario.

> **Access token y refresh token**
>
> La pareja de tokens reparte un compromiso entre seguridad y comodidad. El **access token** es de **vida corta** (minutos): si se filtra, el daño dura poco. El **refresh token** es de **vida larga** y se guarda con más cuidado; sirve solo para pedir nuevos access tokens. Así se evita tener que reautenticar al usuario cada pocos minutos *y* se limita la ventana de exposición si un access token cae en malas manos. El refresh token, por su valor, debe almacenarse de forma segura y poder revocarse.

## Buenas prácticas de seguridad

- **Validar siempre la firma.** Un token cuya firma no verifica no es de fiar, punto. Usar una biblioteca probada, no verificar a mano.
- **Comprobar la expiración.** Rechazar tokens caducados (exp); no confiar solo en que el cliente lo respete.
- **HTTPS obligatorio.** Un token viaja como una llave; sin cifrado en tránsito, se puede interceptar.
- **Access tokens de vida corta.** Minutos, no días; reducen el impacto de una filtración.
- **Fijar el algoritmo esperado.** No aceptar el algoritmo que diga el token (evita el ataque de algoritmo none); definirlo en el servidor.
- **No guardar tokens donde el JavaScript de terceros los alcance.** Valorar cookies HttpOnly frente a localStorage según el riesgo de XSS.
- **Poder revocar.** Prever cierre de sesión y revocación de refresh tokens; un JWT firmado es válido hasta que expira si no hay lista de revocación.

> **Atención**
>
> La criptografía de JWT y los flujos de OAuth están llenos de detalles donde un error pequeño abre un agujero grande. No implementes la verificación de firmas ni el flujo de autorización a mano: usá **bibliotecas mantenidas y auditadas** del ecosistema de tu lenguaje, y para OAuth apoyate en el proveedor de identidad. Este consejo enlaza con la seguridad de autenticación más amplia: [passkeys y modelos zero trust](../../hacking/passkeys-autenticacion-sin-contrasena-y-zero-trust/index.md) apuntan a reducir aún más la superficie de ataque de las credenciales.

## Errores frecuentes

- **Creer que el JWT está cifrado.** El payload es legible; nunca poner secretos en él.
- **No validar la expiración ni la firma en el servidor.** Confiar en el cliente es dejar la puerta abierta.
- **Access tokens que duran días o no caducan.** Amplían enormemente el daño de una filtración.
- **Confundir autenticación con autorización.** OAuth 2.0 es autorización; para identidad se usa OpenID Connect.
- **Implementar la verificación criptográfica a mano.** Fuente habitual de vulnerabilidades; usar bibliotecas probadas.
- **Guardar el refresh token sin protección.** Es la llave de larga duración; debe cuidarse y poder revocarse.
- **Aceptar el algoritmo que indica el token.** Permite el ataque de algoritmo none; fijarlo en el servidor.

## Preguntas frecuentes

**¿Cuál es la diferencia entre JWT y OAuth 2.0?**
La diferencia entre JWT y OAuth 2.0 es que operan en niveles distintos y resuelven problemas diferentes, aunque suelen usarse juntos, lo que lleva a confundirlos. Un JWT, o JSON Web Token, es un formato de token, es decir, una manera estandarizada de representar información de forma compacta y firmada dentro de una cadena de texto que se puede transmitir fácilmente; responde a la pregunta de cómo transportar y verificar datos de una sesión o de una identidad de modo que quien los reciba pueda comprobar que son auténticos y no han sido alterados. OAuth 2.0, en cambio, es un protocolo o marco de autorización, es decir, un conjunto de reglas y flujos que definen cómo una aplicación puede obtener permiso para acceder a recursos en nombre de un usuario sin necesidad de manejar directamente su contraseña; responde a la pregunta de cómo conceder acceso de forma segura y delegada, y es lo que hay detrás de opciones como iniciar sesión con una cuenta de un proveedor externo. La relación entre ambos es que OAuth 2.0 orquesta la obtención de tokens, y esos tokens que entrega pueden tener, y en la práctica moderna suelen tener, el formato de un JWT. Dicho de forma sencilla, JWT describe cómo se ve el token, mientras que OAuth 2.0 describe cómo se consigue el permiso. Es perfectamente posible usar JWT sin OAuth, por ejemplo para gestionar la propia sesión de un usuario tras un inicio de sesión clásico con usuario y contraseña, y también es posible usar OAuth con tokens que no sean JWT. Conviene mencionar además OpenID Connect, que es una capa construida sobre OAuth 2.0 que añade la parte de autenticación, es decir, la de saber quién es el usuario, mediante un token de identidad, ya que OAuth 2.0 por sí solo se ocupa de la autorización y no de establecer la identidad. Entender que uno es un formato y el otro un protocolo, y que se complementan, es el primer paso para implementar autenticación correctamente y sin confusiones.

**¿Qué contiene un JSON Web Token?**
Un JSON Web Token contiene tres partes bien diferenciadas, unidas por puntos dentro de una única cadena de texto, y cada una cumple una función concreta. La primera parte es la cabecera, que incluye metadatos sobre el propio token, principalmente el tipo y el algoritmo de firma que se ha utilizado para protegerlo. La segunda parte es la carga útil, conocida como payload, que contiene las afirmaciones o claims, es decir, los datos que el token transporta; entre ellos suele haber un identificador del sujeto o usuario, información como su nombre o sus roles y permisos, y datos temporales como el momento en que se emitió el token y el momento en que expira, que es fundamental para limitar su validez. La tercera parte es la firma, que se genera combinando la cabecera y el payload con una clave, secreta o privada según el algoritmo, y que sirve para garantizar dos cosas: que el contenido no ha sido alterado desde que se emitió y que fue emitido por quien dice haberlo emitido. Un aspecto crucial que hay que comprender es que la cabecera y el payload no están cifrados, sino simplemente codificados en Base64, lo que significa que cualquiera que tenga el token puede decodificar y leer su contenido con facilidad. Por esa razón, en el payload jamás deben incluirse datos secretos o sensibles como contraseñas, claves o información confidencial, ya que serían visibles. Lo que hace fiable a un JWT no es la confidencialidad de sus datos, sino la firma: si alguien modifica cualquier parte del contenido, la firma deja de ser válida y el servidor que verifica el token lo rechaza. Por tanto, la seguridad de un JWT descansa en verificar siempre su firma y su fecha de expiración en cada uso, y en transportarlo siempre por un canal cifrado mediante HTTPS para evitar que sea interceptado, y no en ocultar lo que lleva dentro.

**¿Cómo funciona el flujo de autorización de OAuth 2.0?**
El flujo de autorización más habitual y recomendado de OAuth 2.0 es el llamado flujo de código de autorización, y su idea central es que la aplicación nunca maneje la contraseña del usuario, sino que delegue la autenticación en un proveedor de identidad de confianza. El proceso comienza cuando la aplicación redirige al usuario hacia el proveedor de identidad, por ejemplo el servicio de una gran plataforma, indicando qué permisos solicita y a qué dirección debe volver el usuario después. A continuación, el usuario se autentica directamente en el proveedor, introduciendo allí sus credenciales, que la aplicación no ve en ningún momento, y da su consentimiento a los permisos que se le solicitan. Una vez aceptado, el proveedor devuelve al usuario a la aplicación acompañado de un código de autorización, que es un valor temporal y de un solo uso. Entonces la aplicación, normalmente desde su parte de servidor para mayor seguridad, canjea ese código de autorización por los tokens, obteniendo un token de acceso y habitualmente también un token de refresco. Con el token de acceso, la aplicación puede realizar llamadas a la interfaz de programación protegida en nombre del usuario, incluyéndolo en cada petición como prueba de que tiene permiso. Como el token de acceso tiene una vida corta por seguridad, cuando caduca la aplicación utiliza el token de refresco para obtener un nuevo token de acceso sin necesidad de volver a molestar al usuario pidiéndole que se autentique de nuevo. Este diseño reparte de forma inteligente el equilibrio entre seguridad y comodidad, ya que el token de acceso de vida corta limita el daño en caso de filtración, mientras que el token de refresco, guardado con más cuidado y revocable, permite mantener la sesión sin fricción. Para aplicaciones que se ejecutan en entornos públicos, como las aplicaciones móviles o las de página única, este flujo se refuerza con una extensión de seguridad que protege el intercambio del código, evitando que un atacante que lo intercepte pueda aprovecharlo. En conjunto, este flujo permite conceder acceso delegado de forma segura sin exponer nunca las credenciales del usuario a la aplicación.

**¿Es seguro guardar datos en un JWT?**
Depende de qué datos y con qué expectativa, porque un JWT protege la integridad de los datos que contiene pero no su confidencialidad, y confundir ambas cosas es una fuente habitual de errores de seguridad. La parte del token que transporta los datos, el payload, no está cifrada, sino únicamente codificada en un formato que cualquiera puede revertir con herramientas comunes, de modo que cualquier persona que consiga el token puede leer perfectamente su contenido. Por eso, guardar en un JWT datos secretos o sensibles, como contraseñas, números de tarjetas, claves o cualquier información confidencial, es inseguro y no debe hacerse nunca, ya que quedarían expuestos a quien intercepte o inspeccione el token. En cambio, sí es apropiado y habitual guardar en el payload datos de identidad y de sesión que no sean secretos, como el identificador del usuario, sus roles o permisos, y las marcas de tiempo de emisión y expiración, porque esa información sirve para que el servidor sepa quién hace la petición y qué puede hacer, y no representa un problema aunque sea legible. La garantía que sí ofrece el JWT sobre esos datos es que no pueden ser manipulados sin invalidar el token: gracias a la firma, si alguien intentara, por ejemplo, cambiar su rol de usuario normal a administrador editando el payload, la firma dejaría de coincidir y el servidor rechazaría el token, siempre y cuando el servidor verifique correctamente la firma en cada petición, que es imprescindible. En resumen, un JWT es seguro para transportar datos de identidad no confidenciales de forma verificable, pero no debe usarse como si fuera un contenedor cifrado para secretos; si realmente se necesitara transportar información confidencial dentro de un token, existen variantes cifradas de los tokens, pero para el uso normal la regla práctica es clara: en el payload van datos de identidad y validez, nunca secretos, y la seguridad se apoya en la firma, la expiración y el transporte por HTTPS.

**¿Debo implementar JWT y OAuth por mi cuenta?**
No es recomendable implementar por tu cuenta la criptografía de los JWT ni los flujos de OAuth 2.0 desde cero, porque ambos están llenos de detalles delicados en los que un error aparentemente menor puede abrir una vulnerabilidad grave, y ya existen bibliotecas y servicios maduros, mantenidos y auditados que resuelven estos problemas correctamente. En el caso de los JWT, la generación y sobre todo la verificación de la firma deben hacerse con una biblioteca establecida del ecosistema de tu lenguaje, en lugar de programar la validación a mano, porque hay errores clásicos que las bibliotecas bien diseñadas evitan, como aceptar el algoritmo que el propio token indica en su cabecera, lo que da lugar a ataques conocidos en los que un atacante fuerza que no se verifique la firma; una buena práctica es fijar en el servidor el algoritmo esperado y no confiar en el que declare el token. En el caso de OAuth 2.0, lo más sensato es apoyarse en los proveedores de identidad y en las bibliotecas cliente oficiales o ampliamente adoptadas, que implementan los flujos correctamente, incluyendo las extensiones de seguridad necesarias para aplicaciones públicas, en lugar de construir el flujo manualmente. Además, para muchos proyectos es razonable delegar toda la autenticación en servicios especializados de gestión de identidad, que ofrecen inicio de sesión, emisión y renovación de tokens, revocación y otras funciones de forma robusta. Esto no significa que no debas entender cómo funcionan JWT y OAuth, todo lo contrario: comprender bien los conceptos, el significado de cada parte del token, el flujo de autorización y las buenas prácticas de seguridad es imprescindible para usar correctamente esas bibliotecas y servicios, configurarlos de forma segura y diagnosticar problemas. La recomendación, por tanto, es aprender a fondo el modelo y las buenas prácticas, pero apoyar la implementación real en herramientas probadas, validando siempre la firma y la expiración, usando HTTPS, manejando expiraciones cortas para los tokens de acceso y previendo la revocación, en lugar de reinventar mecanismos de seguridad críticos.

**¿Dónde debo guardar el token en una aplicación web?**
La cuestión de dónde guardar el token en una aplicación web no tiene una única respuesta universal, sino que depende del modelo de amenazas de la aplicación, y se trata de elegir la opción menos mala frente a los distintos riesgos, principalmente el robo de tokens mediante ataques de tipo cross site scripting y los ataques de falsificación de peticiones. Las dos ubicaciones que se suelen considerar en el navegador son el almacenamiento local del navegador y las cookies. Guardar el token en el almacenamiento local es cómodo y sencillo desde el punto de vista del desarrollo, pero tiene el inconveniente de que ese almacenamiento es accesible desde el código JavaScript de la página, de modo que si la aplicación sufre una vulnerabilidad de cross site scripting, un atacante podría leer el token y robarlo; por eso esta opción es más arriesgada frente a ese tipo de ataques. Guardar el token en una cookie marcada con los atributos adecuados, en particular el atributo que impide que el JavaScript de la página acceda a ella, protege mejor frente al robo por cross site scripting, ya que el token no queda expuesto al código de la página; a cambio, el uso de cookies introduce la necesidad de protegerse frente a la falsificación de peticiones entre sitios, lo que se consigue con atributos de la propia cookie que limitan cuándo se envía y con las defensas habituales contra ese tipo de ataque. En cualquier caso, hay medidas transversales imprescindibles: usar siempre HTTPS para que el token no viaje en claro y pueda ser interceptado, mantener los tokens de acceso con una vida corta para limitar el impacto de un posible robo, y guardar con especial cuidado el token de refresco, que por su larga duración es más valioso. La recomendación práctica es analizar los riesgos concretos de la aplicación, tender a proteger los tokens del acceso por parte de scripts cuando el riesgo de cross site scripting es relevante, aplicar las defensas correspondientes según la ubicación elegida, y apoyarse en las prácticas recomendadas y en bibliotecas y servicios de autenticación bien mantenidos en lugar de improvisar la gestión del almacenamiento de credenciales.

## Fuentes

Documentación oficial y material de la comunidad consultados para esta guía. Fecha de consulta: 28 de julio de 2026.

### Aportes de la comunidad Underc0de

1. **Underc0de, foro.** [Sección Desarrollo web](https://underc0de.org/foro/desarrollo-web/). Autenticación en aplicaciones web.
2. **Underc0de, foro.** [Sección Programación](https://underc0de.org/foro/programacion/). Seguridad de APIs.

### Documentación oficial

1. **IETF.** [RFC 7519: JSON Web Token](https://datatracker.ietf.org/doc/html/rfc7519). Especificación del formato JWT.
2. **IETF.** [RFC 6749: The OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749). Especificación de OAuth 2.0.
3. **OWASP.** [JSON Web Token Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html). Buenas prácticas de seguridad con JWT.
4. **IETF.** [RFC 8725: JWT Best Current Practices](https://datatracker.ietf.org/doc/html/rfc8725). Prácticas recomendadas para JWT.

## Guías relacionadas

- [Crear una API REST](../como-crear-y-consumir-una-api-rest/index.md)
- [API con Node.js y Express](../como-crear-una-api-con-nodejs-y-express/index.md)
- [Seguridad de APIs REST](../../hacking/seguridad-de-apis-rest-autenticacion-permisos-y-validaciones/index.md)
- [Passkeys y Zero Trust](../../hacking/passkeys-autenticacion-sin-contrasena-y-zero-trust/index.md)
- [Índice de Programación](../index.md)
