JWT (JSON Web Token) es un formato compacto para transferir datos entre partes como un objeto JSON protegido por una firma digital. El token puede firmarse usando HMAC (clave simétrica) o RSA/ECDSA (par asimétrico), lo que garantiza la integridad y autenticidad de los datos. Según IETF RFC 7519, 2015, JWT se utiliza en millones de aplicaciones para autenticación, intercambio seguro de claims y como formato de ID Token en OpenID Connect.
Puntos Clave
JSON Web Token (JWT) es un estándar abierto (RFC 7519) que define una forma compacta y autocontenida de transmitir información entre partes como un objeto JSON. La información en JWT se denomina claims — afirmaciones sobre el sujeto (usuario) y atributos adicionales. Cada claim es un par clave-valor: identificador de usuario, rol, tiempo de expiración, emisor.
JWT se llama autocontenido porque toda la información necesaria para la verificación está dentro del propio token. El servidor no necesita acceder a una base de datos o almacenamiento externo para verificar la validez del token — solo necesita comprobar la firma. Esta propiedad hace que JWT sea ideal para sistemas distribuidos y arquitecturas de microservicios, donde múltiples servicios deben autenticar solicitudes sin un almacén de sesiones compartido.
Según Auth0, 2025, más del 65% de las aplicaciones móviles y web utilizan JWT como formato principal de token para autenticación de API, superando a los tokens opacos y los identificadores de sesión.
JWT consta de tres partes separadas por puntos: header.payload.signature. Cada parte es un JSON codificado en Base64url. Examinemos cada parte en detalle.
Header contiene dos campos obligatorios: alg (algorithm — algoritmo de firma) y typ (type — tipo de token, siempre “JWT”). El algoritmo puede ser simétrico (HS256 — HMAC con SHA-256) o asimétrico (RS256 — RSA con SHA-256, ES256 — ECDSA con P-256). Los algoritmos asimétricos son preferibles porque permiten al cliente verificar la firma sin poseer la clave secreta.
Ejemplo de un header decodificado:
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-id-1"
}
Payload contiene claims — afirmaciones sobre el sujeto. Los claims se dividen en tres tipos: registrados (iss, sub, aud, exp, nbf, iat, jti), públicos (definidos por el desarrollador en el Registro IANA) y privados (acordados entre las partes). sub (subject) es el identificador único del usuario. exp (expiration) es la marca de tiempo de expiración del token. iss (issuer) es el emisor del token.
{
"sub": "user-abc-123",
"iss": "https://auth.example.com",
"aud": "my-mobile-app",
"exp": 1812345678,
"iat": 1812342078,
"role": "premium_user"
}
Signature se crea aplicando el algoritmo de firma a la concatenación del header y el payload usando una clave secreta o privada. La fórmula: HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret) para HMAC, o RSASHA256(...) para algoritmo asimétrico. El destinatario calcula la firma de la misma manera y la compara con la recibida — si coinciden, los datos no han sido alterados.
El flujo de trabajo con JWT consta de dos fases: creación (emisión) del token por el servidor de autenticación y verificación del token por el cliente o servidor de recursos. El servidor de autenticación recibe las credenciales del usuario, crea un payload con claims y lo firma. El JWT resultante se envía al cliente en respuesta a una solicitud de inicio de sesión o en el cuerpo de respuesta de OAuth 2.0 / OpenID Connect.
En aplicaciones móviles, JWT se utiliza de la siguiente manera: después de un inicio de sesión exitoso, el usuario recibe un token de acceso en formato JWT. La aplicación lo almacena en un almacenamiento seguro (Keychain en iOS, EncryptedSharedPreferences en Android). Con cada solicitud a la API, la aplicación añade el encabezado Authorization: Bearer <token>. El servidor API verifica la firma del JWT, extrae los claims y toma decisiones de acceso basadas en ellos — sin consultar la base de datos.
Según Google Codelabs, 2025, el uso de JWT en Firebase Authentication reduce la cantidad de solicitudes al servidor de autenticación en un 40–60% en comparación con los tokens de sesión, ya que los datos se verifican localmente en cada microservicio. Esto es especialmente importante para arquitecturas de alta carga, donde cada milisegundo de latencia afecta la experiencia del usuario. Con 50 000 solicitudes por minuto, cambiar a JWT puede ahorrar hasta 10 instancias de servidor que manejan solicitudes de introspección.
JWT y Session Token resuelven el mismo problema — autenticación de solicitudes — pero difieren fundamentalmente en arquitectura. Session Token es una cadena de identificación aleatoria que hace referencia a datos de sesión almacenados en el servidor (stateful). JWT es un token autocontenido que contiene todos los datos dentro de sí mismo (stateless).
| Parámetro | JWT | Session Token |
|---|---|---|
| Almacenamiento de datos | Dentro del token (autocontenido) | En el servidor (almacenamiento de sesión) |
| Escalado | No requiere almacenamiento compartido | Requiere Redis/DB para multi-servidor |
| Revocación de token | Compleja (necesita lista negra) | Simple (eliminar sesión de la BD) |
| Tamaño | Grande (500–2000 bytes) | Pequeño (16–64 bytes) |
| Verificación de firma | Criptográfica | Ninguna (comparación de cadenas) |
JWT destaca en sistemas distribuidos: los microservicios pueden verificar el token localmente sin un almacén compartido. Por ejemplo, en una arquitectura con cinco microservicios, cada servicio verifica JWT en 1–2 ms sin una llamada de red, mientras que un session token requiere una consulta centralizada a Redis en cada solicitud, añadiendo 10–30 ms de latencia. Sin embargo, JWT es difícil de revocar — una vez emitido, es válido hasta su expiración. Session Token es fácil de revocar eliminando el registro de la BD o Redis.
Para aplicaciones móviles, un enfoque combinado — JWT con vida útil corta (15–30 minutos) y Refresh Token — ofrece un equilibrio entre rendimiento y seguridad. JWT se utiliza para el acceso a la API, mientras que el refresh token (generalmente opaco) se usa para obtener nuevos JWT. Si un JWT se ve comprometido, el atacante tiene acceso durante 15–30 minutos; si un refresh token se ve comprometido, la sesión se bloquea mediante rotación y detección de reutilización.
La seguridad de JWT depende de una implementación correcta. La vulnerabilidad más común es el ataque “alg none”: un atacante cambia el header del token a “alg”: “none”, y el servidor, sin verificar el algoritmo, acepta el token falsificado. Protección: siempre verificar que el algoritmo en el header coincida con el esperado (RS256, ES256), y rechazar tokens con alg: none.
Las vulnerabilidades de JWT también incluyen: clave secreta débil para HMAC (descifrado en minutos), fuga de clave privada (firmar cualquier dato en nombre del servidor), almacenamiento de datos sensibles en el payload (JWT no cifra, solo firma), ataque de inyección JWK header (inyección de una clave pública personalizada). El uso de bibliotecas confiables — Nimbus JOSE + JWT, jjwt (io.jsonwebtoken), PyJWT — reduce el riesgo de explotar estas vulnerabilidades.
Una medida de seguridad adicional es JWK Thumbprint (RFC 7638): vinculación de una clave pública al token mediante una huella digital en el header. Si el servidor almacena la huella esperada para cada cliente, la inyección JWK header se vuelve imposible — el servidor rechaza cualquier clave que no coincida con la registrada. El OAuth Security Workshop 2025 recomienda JWK Thumbprint como protección obligatoria para todos los JWT utilizados en aplicaciones financieras y médicas.
La biblioteca jjwt (auth0/java-jwt) permite crear y verificar JWT en una aplicación Android en solo unas líneas. En el siguiente ejemplo, el servidor genera un token con sub y role, y el cliente verifica la firma. Para el almacenamiento seguro de la clave secreta en el servidor, use variables de entorno o un HSM (Hardware Security Module) — almacenar la clave en código o un archivo de configuración es un grave error de seguridad.
val secret = "my-256-bit-secret-key-here"
val token = JWT.create()
.withSubject("user-abc-123")
.withIssuer("auth.example.com")
.withClaim("role", "premium_user")
.withExpiresAt(Date(System.currentTimeMillis() + 3600000))
.sign(Algorithm.HMAC256(secret))
// Enviando token al cliente
println("JWT: $token")
fun verifyToken(token: String): Boolean {
return try {
val decoded = JWT.require(Algorithm.HMAC256(secret))
.withIssuer("auth.example.com")
.build()
.verify(token)
// Firma válida, claims extraídos
println("Subject: ${decoded.subject}")
true
} catch (e: Exception) {
println("Token inválido: ${e.message}")
false
}
}
Preguntas Frecuentes
No. JWT se firma, no se cifra — cualquiera puede decodificar el payload Base64 y leer los datos. La información sensible (contraseñas, números de tarjeta, datos personales) debe transmitirse solo en forma cifrada usando JWE (JSON Web Encryption).
Se recomienda ES256 (ECDSA con P-256) — proporciona un nivel de seguridad equivalente a RSA 2048-bit con un tamaño de firma significativamente menor. RS256 es adecuado para compatibilidad con sistemas heredados. HS256 (HMAC) requiere un intercambio seguro de clave secreta, lo que es más difícil en una arquitectura distribuida.
JWT no se puede revocar directamente — es válido hasta exp. Soluciones: usar una vida útil corta (15–30 minutos), mantener una lista negra de jti (JWT ID) revocados en el servidor, o vincular los tokens a una versión de clave secreta. El refresh token se revoca de forma estándar — eliminándolo del almacenamiento.
Bearer token es un concepto: cualquier token que el portador puede usar para acceso. JWT es un formato de token específico. Un Bearer token puede ser un JWT o una cadena opaca. JWT añade autocontención y verificación criptográfica al concepto Bearer.
Un JWT típico con firma RS256 ocupa 500–2000 bytes. Si el payload contiene muchos claims personalizados o se usa una firma asimétrica con una clave grande, el tamaño puede alcanzar 4–5 KB. Esto es significativamente mayor que un session token (16–64 bytes), lo que afecta el tamaño de los encabezados HTTP.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también