¿Qué es JWT? Tokens web JSON explicados con un ejemplo práctico

  1. Inicio
  2. Blog
  3. Desarrollo de software

Desarrollo de software

¿Qué es JWT? Tokens web JSON explicados con un ejemplo práctico

Un JWT permite que un servidor confíe en una solicitud sin buscar nada. Cree uno desde cero, intente manipularlo y observe cómo falla, luego aprenda cuándo los tokens superan las sesiones y cómo usarlos de forma segura.

9 min de lectura
¿Qué es JWT? JSON Web Tokens explicados con un ejemplo práctico

Puntos clave

  • Un JWT es un token compacto y firmado con tres partes: encabezado, carga útil y firma.
  • La firma demuestra que un token no ha sido modificado, por lo que el servidor puede confiar en él sin necesidad de realizar una búsqueda.
  • La carga útil es legible para cualquiera, así que nunca le pongas secretos.
  • Los tokens son difíciles de revocar, así que manténgalos de corta duración y verifíquelos con una biblioteca confiable.

Después de iniciar sesión, ¿cómo sabe un servidor que cada solicitud posterior realmente proviene de usted? Una respuesta popular es un Token web JSON, o JWT, que generalmente se pronuncia “jota”. Es un pequeño dato firmado que el cliente envía con cada solicitud y el servidor puede verificarlo sin tocar una base de datos.

La forma más rápida de entender un JWT es construir uno y luego intentar romperlo. Lo hicimos usando solo la biblioteca estándar de Python, en Python 3.13, y el resultado a continuación proviene de esa ejecución. Este código es para aprender. En una aplicación real, utilice una biblioteca bien mantenida, porque es fácil equivocarse en los detalles de verificación.

¿Qué es un JWT?

JWT es un estándar abierto, definido en RFC 7519, para transmitir reclamaciones entre dos partes como una cadena compacta. Un reclamo es simplemente una declaración, como “el ID de este usuario es 42”. Como el token está firmado, el receptor puede confirmar quién lo emitió y que nadie lo ha alterado.

Piense en una pulsera de festival. El personal en la puerta revisa tu boleto una vez y te entrega una banda que es difícil de falsificar. Después de eso, cada puesto sólo mira a la banda, sin necesidad de llamar a la taquilla. Un JWT funciona de forma muy similar a una API.

Cómo funciona el inicio de sesión de JWT

  1. El usuario envía un nombre de usuario y contraseña al punto final de inicio de sesión.
  2. El servidor los verifica y crea un token firmado.
  3. El cliente almacena el token.
  4. Cada solicitud posterior lo incluye, normalmente en un encabezado: Authorization: Bearer <token>.
  5. El servidor verifica la firma y la caducidad, luego lee las reclamaciones.

El principal beneficio está en el paso 5. El servidor no tiene que buscar una sesión, lo cual resulta conveniente cuando muchos servicios o servidores necesitan verificar el mismo token. Si es nuevo en las API, comience con qué es una API.

Las tres partes de un JWT

Un JWT parece texto aleatorio, pero consta de tres secciones codificadas en Base64URL separadas por puntos. Aquí hay uno que generamos:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiI0MiIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzkzNTAwMDAwLCJleHAiOjE3OTM1MDA5MDB9
.7YfUDH_T-iDh8bMmUT8mmKYwOstzT8Ty--DTTAmQGWM

Hemos agregado saltos de línea para que sea más fácil de leer. Al decodificar las dos primeras partes se obtiene JSON simple:

Header:  {"alg":"HS256","typ":"JWT"}
Payload: {"sub":"42","role":"user","iat":1793500000,"exp":1793500900}
parte Contiene Propósito
encabezado Tipo de token y algoritmo de firma Dice cómo verificar el token.
Carga útil Reclamaciones sobre el usuario o sesión La información real
Firma Un hash de las dos primeras partes, usando una clave. Demuestra integridad y origen.

Reclamaciones estándar

Reclamar Nombre Significado
sub Asunto De quién se trata el token, generalmente una identificación de usuario
es Emisor ¿Quién creó el token?
aud Audiencia ¿A quién está destinado el token?
exp. Caducidad Cuando el token deja de ser válido
eso es Emitido en Cuando fue creado
nbf No antes Cuando empieza a ser válido
jti ID de JWT Una identificación única para este token

También puede agregar reclamos personalizados, como role. Los tiempos son marcas de tiempo de Unix, en segundos. Mantenga la carga útil pequeña, ya que el token viaja con cada solicitud.

Construye uno tú mismo

Crear un token implica codificar las dos partes JSON y luego firmarlas con un secreto usando HMAC-SHA256:

import base64, hashlib, hmac, json

SECRET = b"demo-secret-do-not-use-in-production"

def b64url(data):
    return base64.urlsafe_b64encode(data).rstrip(b"=").decode()

def sign(message):
    return b64url(hmac.new(SECRET, message.encode(), hashlib.sha256).digest())

def create_token(payload):
    header = {"alg": "HS256", "typ": "JWT"}
    parts = [
        b64url(json.dumps(header, separators=(",", ":")).encode()),
        b64url(json.dumps(payload, separators=(",", ":")).encode()),
    ]
    message = ".".join(parts)
    return message + "." + sign(message)

La verificación funciona recalculando la firma y comparándola con la del token. Sólo alguien con el secreto puede producir uno que coincida:

def verify_token(token, now):
    header, payload, signature = token.split(".")
    expected = sign(header + "." + payload)
    if not hmac.compare_digest(signature, expected):
        raise ValueError("bad signature")
    claims = json.loads(b64url_decode(payload))
    if claims["exp"] < now:
        raise ValueError("token expired")
    return claims

Un token válido devolvió sus reclamos como se esperaba. compare_digest se utiliza ya que se ejecuta en tiempo constante, lo que evita la fuga de información por diferencias de tiempo.

Intenta manipularlo

Supongamos que un atacante decodifica la carga útil, cambia "role":"user" a "role":"admin", la codifica nuevamente y conserva la firma anterior. Probamos esto, junto con otros dos ataques:

intento Resultado
Cambió el rol a administrador. mala firma
Usó el token 1 segundo después de su vencimiento. token caducado
Establecí "alg":"none" y eliminé la firma. mala firma

Ese último intento apunta a una verdadera debilidad histórica. Algunas bibliotecas alguna vez confiaron en el propio encabezado del token, por lo que un atacante podría simplemente declarar que no se necesitaba firma. Nuestro código siempre utiliza un algoritmo fijo, por eso fue rechazado. En una biblioteca real, especifique siempre los algoritmos que acepta.

Firmado, no cifrado

Este es el punto más incomprendido sobre los JWT. Nuestro token falsificado fue rechazado, pero su contenido aún era perfectamente legible:

{"sub":"42","role":"admin","iat":1793500000,"exp":1793500900}

Base64URL es una codificación, no una encriptación, y cualquiera puede revertirla sin ninguna clave. La firma impide que las personas cambien los datos, pero no lean. Por lo tanto, nunca coloque contraseñas, números de tarjetas o datos personales privados en una carga útil de JWT. Si el contenido debe ocultarse, utilice tokens cifrados (JWE) o simplemente mantenga los datos en el servidor.

HS256 frente a RS256

Aspecto HS256 RS256 o ES256
Tipo simétrico asimétrico
llaves Un secreto compartido Una clave privada firma, una clave pública verifica
¿Quién puede crear tokens? Cualquiera que tenga el secreto Sólo el titular de la clave privada
Lo mejor para Un servicio o un pequeño grupo de confianza Muchos servicios, terceros, proveedores de identidad.

Con la firma asimétrica, otros servicios pueden verificar tokens sin poder acuñar los suyos propios, lo que limita el daño si uno se ve comprometido.

JWT frente a sesiones

Los JWT a menudo se presentan como un reemplazo moderno de las sesiones. En realidad, cada uno tiene sus ventajas y desventajas:

Aspecto Sesión del servidor JWT
donde vive el estado en el servidor en la ficha
Búsqueda en cada solicitud Generalmente No es necesario
Cerrar sesión o revocar Fácil, elimina la sesión. Duro antes de caducar
Tamaño por solicitud Identificación pequeña Token más grande (el nuestro tenía 161 caracteres)
En muchos servicios Necesita almacenamiento compartido Cada uno puede verificarlo directamente.
Cambiar permisos Se aplica inmediatamente El token antiguo sigue siendo válido hasta que caduque

Para un sitio web tradicional generado por un servidor, una cookie de sesión suele ser más sencilla y segura. Los JWT tienden a tener más sentido para las API consumidas por varios servicios o para clientes móviles.

Consejo: No elija JWT solo porque suena sin estado. Muchos sistemas reales agregan una lista de denegados o una verificación de base de datos para admitir el cierre de sesión, lo que recupera la búsqueda que JWT debía evitar.

Dónde almacenar tokens en un navegador

Ubicación riesgo XSS riesgo CSRF Notas
almacenamiento local Alto, como los scripts pueden leerlo. Bajo Simple, pero expuesto a cualquier script inyectado.
Cookie HttpOnly Más bajo, ya que los scripts no pueden leerlo. Necesita protección Utilice Secure y SameSite
variable en memoria inferior Bajo Se perdió al actualizar, por lo que necesita un flujo de actualización

Muchas guías de seguridad favorecen las cookies HttpOnly, Secure, SameSite para aplicaciones web. Cualquiera que elijas, utiliza siempre HTTPS. Para enviar un token desde JavaScript, consulte nuestro tutorial de JavaScript Fetch API.

Actualizar fichas

El vencimiento corto limita el daño de un token robado, pero nadie quiere iniciar sesión cada 15 minutos. La solución habitual utiliza dos tokens:

  • Token de acceso: de corta duración, como minutos, y se envía con cada solicitud de API.
  • Token de actualización: tiene una vida más larga, se almacena con más cuidado y se usa solo para obtener nuevos tokens de acceso.

El servidor realiza un seguimiento de los tokens de actualización, por lo que puede revocarlos, lo que le brinda un cierre de sesión práctico. Rotarlos en cada uso también le ayuda a detectar robos, porque una ficha antigua robada se vuelve a reproducir.

Errores de seguridad comunes

  • Decodificar sin verificar. Leer una carga útil no la hace confiable. Comprueba siempre la firma.
  • Aceptar cualquier algoritmo. Establecer una lista explícita de algoritmos permitidos.
  • Usar un secreto débil. Los secretos breves se pueden descifrar sin conexión. Utilice un valor aleatorio largo y manténgalo fuera del control de fuente.
  • Omitiendo el vencimiento. Los tokens sin exp pueden funcionar para siempre si son robados.
  • No marcar iss y aud. De lo contrario, un token emitido para un servicio puede ser aceptado por otro.
  • Confiar en afirmaciones obsoletas. Una función dentro de un token puede estar desactualizada hasta que caduque.
  • Tokens de registro. Cualquiera que lea sus registros podría reutilizarlos.
  • No probar rutas de falla. Agregue pruebas para tokens vencidos y modificados, así como también válidos. Nuestra guía Pruebas de API con Postman puede resultar útil.

Conclusión

Un JWT son datos firmados en los que un servidor puede confiar sin una búsqueda, no un contenedor secreto ni una actualización automática a lo largo de las sesiones. Utilice una caducidad corta, verifique todo con una biblioteca mantenida y mantenga los datos privados fuera de la carga útil. Para comprobarlo usted mismo, ejecute un pequeño script como el nuestro, cambie un carácter de un token y observe cómo falla la verificación.

Preguntas frecuentes

¿Para qué se utiliza un JWT?

Los JWT se utilizan principalmente para autenticación y autorización en API. Después de iniciar sesión, un cliente envía el token con cada solicitud y el servidor lo verifica para identificar al usuario.

¿Está cifrado un JWT?

Generalmente no. Un JWT estándar está firmado y codificado, por lo que cualquiera puede leer su carga útil. La firma sólo impide cambios. Los tokens cifrados utilizan un formato relacionado llamado JWE.

¿Cuánto tiempo debe durar un JWT?

Los tokens de acceso suelen ser de corta duración, a menudo minutos en lugar de días. Combínelos con un token de actualización, para que los usuarios no tengan que iniciar sesión constantemente.

¿Se puede revocar un JWT?

No por sí solo, ya que sigue siendo válido hasta que caduque. La revocación requiere un seguimiento del lado del servidor, como una lista de denegados, que elimina parte del beneficio sin estado.

¿JWT es mejor que las sesiones?

Ninguno de los dos es siempre mejor. Las sesiones son más sencillas de revocar y se adaptan a muchos sitios web, mientras que los JWT se adaptan a las API y servicios que necesitan verificar la identidad de forma independiente.

sigue aprendiendo

Trabajar con Stack Quora

¿Necesitas ayuda con pruebas, WordPress o SEO?

Ayudamos a los equipos a enviar mejor software y hacer crecer sus sitios. Cuéntenos en qué está trabajando y le sugeriremos un siguiente paso claro.

Sigue leyendo

Más guías sobre testing, IA y desarrollo moderno

¿Te gustó este artículo? Elige un tema y salta directo a nuestros tutoriales más recientes.

Inteligencia artificial

Explicación de las alucinaciones de la IA: por qué los modelos de lenguaje inventan cosas y cómo reducirlas

Se explicaron las alucinaciones de la IA: qué son, por qué los modelos de lenguaje las producen, tipos comunes, cómo reducirlas con conexión a tierr…

Leer artículo →
DevOps

Explicación de las variables de entorno: archivos .env, secretos y configuración bien hechos

Variables de entorno explicadas con ejemplos de Python que ejecutamos: leerlas y configurarlas, por qué cada valor es una cadena, archivos .env, her…

Leer artículo →
Desarrollo de software

Explicación de la limitación de velocidad de API: algoritmos, encabezados y manejo de errores 429

La limitación de la tasa de API se explica con una simulación que ejecutamos: depósito de tokens, ventana fija, ventana deslizante, 429 respuestas, …

Leer artículo →
Automatización de pruebas

Burlarse en Python: unittest.mock, patch y los errores que hacen que las pruebas mientan

Burlarse en Python con unittest.mock, probado: Mock y return_value, side_effect, parches donde se usa un nombre, especificación y autospec, fechas d…

Leer artículo →
Pruebas de software

Explicación de la cobertura del código: cobertura de línea versus sucursal y lo que realmente significa 100%

Cobertura del código explicada con una ejecución real de cobertura.py: cobertura de línea, rama y condición, lectura de un informe, por qué una cobe…

Leer artículo →
Bases de datos y SQL

DELETE vs TRUNCATE vs DROP en SQL: diferencias, reversión y cuándo usar cada uno

DELETE vs TRUNCATE vs DROP explicado con SQL probado: qué elimina cada uno, reversión, activadores, restablecimiento de identidad, velocidad y en qu…

Leer artículo →
Bases de datos y SQL

Vistas SQL explicadas: cree, use y evite los errores, con ejemplos

Vistas SQL explicadas con consultas que ejecutamos: creación de una vista, resultados en vivo, ocultación de columnas, rendimiento, vistas actualiza…

Leer artículo →
Desarrollo de software

Interfaz TypeScript versus tipo: diferencias reales, probadas con el compilador

Interfaz TypeScript versus tipo, verificado con el compilador real: qué pueden hacer ambos, qué puede hacer solo uno, fusión de declaraciones, exten…

Leer artículo →
Desarrollo de software

Python *args y **kwargs explicados: funciones flexibles con ejemplos claros

Python *args y **kwargs explicados con el código que ejecutamos: empaquetado y desempaquetado, orden de parámetros, argumentos solo de palabras clav…

Leer artículo →
Desarrollo de software

Funciones Lambda de Python: sintaxis, usos reales y cuándo no utilizarlas

Funciones lambda de Python explicadas con el código que ejecutamos: sintaxis, clasificación con clave, mapa y filtro, cierres, trampa de enlace tard…

Leer artículo →
Inteligencia artificial

¿Qué son los agentes de IA? Cómo funcionan, con un bucle de agente simple que puedes ejecutar

¿Qué son los agentes de IA? Una guía sencilla sobre el bucle del agente, las herramientas, la memoria y las barreras de seguridad, con un pequeño bu…

Leer artículo →
DevOps

Monitoreo versus observabilidad: la verdadera diferencia, con registros, métricas y seguimientos

Explicación del monitoreo versus observabilidad: fallas conocidas y desconocidas, registros, métricas y seguimientos, un recorrido por incidentes de…

Leer artículo →
DevOps

Docker Volumes versus Bind Mounts: persistir los datos del contenedor de la manera correcta

Se explican los volúmenes de Docker frente a los montajes de enlace: por qué desaparecen los datos del contenedor, volúmenes con nombre, montajes de…

Leer artículo →
Automatización de pruebas

TDD vs BDD: diferencias clave, una función creada en ambos sentidos y cuándo usar cada una

TDD vs BDD explicado con una característica de descuento construida en ambos sentidos: refactor rojo-verde con el código que ejecutamos, escenarios …

Leer artículo →
Pruebas de software

Pruebas de Aceptación de Usuario (UAT): Proceso, Lista de Verificación y Ejemplos Reales

Explicación de las pruebas de aceptación del usuario: quién las ejecuta, en qué se diferencia del control de calidad, un proceso de siete pasos, una…

Leer artículo →
Bases de datos y SQL

Valores NULL de SQL explicados: IS NULL, COALESCE, NULLIF y las trampas que se deben evitar

Los valores NULL de SQL se explican con las consultas que ejecutamos: lógica de tres valores, IS NULL, COALESCE, NULLIF, cómo los agregados, las uni…

Leer artículo →
Bases de datos y SQL

Declaración SQL CASE WHEN: sintaxis, ejemplos reales y errores comunes

CASO SQL CUANDO se explicó con las consultas que ejecutamos: formularios simples y buscados, orden de condiciones, pivotes con SUMA, trucos COUNT, c…

Leer artículo →
Desarrollo de software

¿Qué es JWT? Tokens web JSON explicados con un ejemplo práctico

¿Qué es JWT? JSON Web Tokens explicó: las tres partes, un token creado y manipulado en el código que ejecutamos, JWT vs sesiones, almacenamiento, to…

Leer artículo →
Desarrollo de software

Explicación del bucle de eventos de JavaScript: pila de llamadas, microtareas y temporizadores con ejemplos

El bucle de eventos de JavaScript explicado con el código que ejecutamos: pila de llamadas, colas de tareas y microtareas, por qué setTimeout 0 no e…

Leer artículo →
Desarrollo de software

Explicación de los generadores y el rendimiento de Python: ahorre memoria con ejemplos reales

Los generadores de Python y el rendimiento se explican con el código que ejecutamos: cómo se pausan y reanudan, midieron el ahorro de memoria, canal…

Leer artículo →
Inteligencia artificial

¿Qué son las incrustaciones? Los vectores y la similitud del coseno se explican de forma sencilla

¿Qué son las incrustaciones? Una guía en lenguaje sencillo sobre vectores, similitud de cosenos y búsqueda semántica, con un pequeño ejemplo que eje…

Leer artículo →
DevOps

Implementación azul-verde versus implementación canaria: diferencias, compensaciones y cómo elegir

Explicación de la implementación azul-verde versus canaria: cómo funciona cada uno, costo, riesgo y reversión, agrupación estable de usuarios que pr…

Leer artículo →
Automatización de pruebas

Pruebas inestables: qué las causa y cómo solucionarlas para siempre

Pruebas inestables explicadas con demostraciones que realizamos: las causas principales, cómo confirmar y diagnosticar una, correcciones adecuadas p…

Leer artículo →
Pruebas de software

Pruebas de carga frente a pruebas de estrés: diferencias, métricas y ejemplos de k6

Explicación de las pruebas de carga frente a las pruebas de estrés: qué prueba cada una, pruebas de picos y de absorción, las métricas que importan,…

Leer artículo →
Pruebas de software

Caso de prueba frente a escenario de prueba: diferencias clave, ejemplos y cuándo utilizar cada uno

Caso de prueba versus escenario de prueba explicado: definiciones claras, una tabla en paralelo, una función de restablecimiento de contraseña tomad…

Leer artículo →
Bases de datos y SQL

Optimización de consultas SQL: lea planes de ejecución y corrija consultas lentas, con tiempos

Optimización de consultas SQL probada en un millón de filas: lea planes de ejecución, agregue los índices correctos, corrija filtros no sargables, u…

Leer artículo →
Bases de datos y SQL

SQL UNION vs UNION ALL: diferencias, ejemplos y rendimiento probado

SQL UNION vs UNION ALL explicado con consultas que ejecutamos: duplicados, las reglas que siguen ambos, un error de datos real, rendimiento medido, …

Leer artículo →
Desarrollo de software

Tutorial de JavaScript Fetch API: GET, POST, manejo de errores y tiempos de espera

Un tutorial de JavaScript Fetch API probado en un servidor local: GET y POST, por qué 404 no arroja, un asistente reutilizable, cadenas de consulta,…

Leer artículo →
Desarrollo de software

Manejo de archivos Python: lectura, escritura, CSV, JSON y pathlib con ejemplos

El manejo de archivos Python se explica con el código que ejecutamos: modos abiertos, lectura de archivos grandes, CSV, JSON, pathlib, archivos bina…

Leer artículo →
Desarrollo de software

Clases y objetos de Python: tutorial de programación orientada a objetos con ejemplos reales

Clases y objetos de Python explicados con el código que ejecutamos: __init__, métodos, atributos de clase versus instancia, herencia, propiedades, m…

Leer artículo →
Desarrollo de software

Git merge vs rebase: diferencias, ejemplos y cuándo usar cada uno

Git merge vs rebase explicado con salida real del log, una tabla comparativa, la regla de oro del rebase y un flujo de trabajo seguro para equipos.

Leer artículo →
Desarrollo de software

List comprehension en Python: sintaxis, ejemplos y cuándo evitarla

List comprehension en Python explicada: sintaxis, filtros, if-else, bucles anidados, tiempos medidos y cuándo es mejor un bucle for normal.

Leer artículo →