Verificar la firma de un JSON Web Token (JWT)
- Panel
- Documentación
- API
¿Por qué verificar la firma de un JWT?
Un JSON Web Token (JWT) se descompone en tres partes separadas por puntos:
header.payload.signature. Decodificar un JWT consiste simplemente en leer las dos primeras
partes (que son Base64URL). Cualquiera puede hacerlo, y cualquiera puede fabricar
un JWT con el payload que elija. Lo que hace que un JWT sea digno de confianza es únicamente la
firma: sin verificación, aceptar un JWT equivale a dejar entrar en su casa a cualquier persona que
diga ser alguien, sin pedirle documento de identidad.
Esta herramienta verifica la firma de un JWT a partir de una clave. No se limita a decodificar: recalcula la firma a partir del header, del payload y de su clave y, después, la compara con la firma del token. Si las dos coinciden, el token es auténtico. Si no, ha sido forjado, modificado o firmado con otra clave.
La verificación es la piedra angular de toda arquitectura que utiliza JWT para
la autenticación o la autorización: sin firma válida, el payload puede mentir.
Un atacante que modificara "role":"user" en "role":"admin" no tendría ninguna
dificultad para hacerlo si el servidor solo verificara el formato del token y no su firma.
Algoritmos habituales
La especificación JWT (RFC 7518, JSON Web Algorithms) define varias familias de algoritmos. Estas son las más utilizadas en producción:
- HMAC (HS256, HS384, HS512): firma simétrica basada en HMAC-SHA. La misma clave secreta sirve para firmar y verificar. Sencilla de implementar, eficiente, pero toda parte capaz de verificar el token también es capaz de emitirlo. Adaptada a escenarios en los que el emisor y el verificador son el mismo equipo o el mismo servicio.
- RSA (RS256, RS384, RS512): firma asimétrica. La clave privada firma, la clave pública verifica. Ideal cuando el emisor y los verificadores son entidades distintas (OAuth2, OpenID Connect, federación de identidad). Es el algoritmo preferido por la mayoría de proveedores de identidad públicos.
- ECDSA (ES256, ES384): firma asimétrica sobre curvas elípticas. Misma lógica que RSA (clave privada para firmar, clave pública para verificar) pero con claves y firmas más compactas para un nivel de seguridad equivalente. Cada vez más extendida en las arquitecturas modernas.
Cómo proporcionar la clave
El formato de la clave esperada depende del algoritmo declarado en el header del JWT:
- HS256, HS384, HS512: la clave es una cadena secreta (string).
Es el secreto compartido con el emisor, a menudo almacenado en una variable de entorno como
JWT_SECRET. Sin formato particular, solo el valor en bruto. - RS256, RS384, RS512: la clave es una clave pública RSA en formato PEM,
que empieza por
-----BEGIN PUBLIC KEY-----y termina por-----END PUBLIC KEY-----. Conserve los saltos de línea tal cual, si no OpenSSL se niega a parsearla. - ES256, ES384: la clave es una clave pública ECDSA en formato PEM, sobre la curva correspondiente (P-256 para ES256, P-384 para ES384).
Ejemplo de clave pública RSA esperada
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxe...
...vQIDAQAB
-----END PUBLIC KEY-----
¿Cómo funciona la verificación?
Nuestro servidor reproduce exactamente la operación que ha realizado el emisor:
- Separa el JWT en header, payload y firma.
- Concatena
base64url(header) + "." + base64url(payload). - Para HMAC, calcula un HMAC-SHA-256/384/512 con su clave secreta y, después, compara con la
firma recibida mediante
hash_equals(comparación en tiempo constante para evitar ataques temporales). - Para RSA, llama a
openssl_verifycon su clave pública en formato PEM.
Casos de uso
- Depuración de autenticación API: recibe un 401, verifica si su token está firmado con la clave esperada.
- Validación de un token recibido de un proveedor: un partner (Auth0, Keycloak, Cognito, Okta) le envía JWT firmados en RS256; quiere confirmar que efectivamente proceden de él con su clave pública.
- Auditoría de seguridad: verificar que un servicio de terceros firma correctamente sus tokens con un algoritmo robusto, y no en HS256 con un secreto débil.
- Pruebas manuales: verificar que un JWT generado por su código pasa la verificación con la clave pública proporcionada.
- Verificación rápida de un token recibido: durante la integración de un SSO o de una API de partner, verificar en pocos segundos que la cadena firma/clave funciona antes de escribir la menor línea de código.
Cómo utilizar la herramienta
- Pegue el JWT completo (las tres partes separadas por puntos).
- Indique la clave adaptada al algoritmo del header:
- Para HS256, HS384 o HS512, la clave es la cadena secreta
compartida con el emisor. Es una cadena libre, a menudo almacenada en una
variable de entorno como
JWT_SECRET. - Para RS256, RS384 o RS512, la clave es la clave pública en formato
PEM, que empieza por
-----BEGIN PUBLIC KEY-----y termina por-----END PUBLIC KEY-----.
- Para HS256, HS384 o HS512, la clave es la cadena secreta
compartida con el emisor. Es una cadena libre, a menudo almacenada en una
variable de entorno como
- Inicie la verificación. La herramienta muestra el estado (válido o no válido) y el payload decodificado.
Errores habituales que evitar
- Algoritmo "none": la spec autoriza
alg: none, que significa "sin firma". Un fallo clásico consiste en fabricar un token con ese header con la esperanza de que el servidor lo acepte. Nuestra herramienta rechaza sistemáticamente los tokens conalg: none. - Confusión HMAC vs RSA (algorithm confusion): un atacante cambia el algoritmo
RS256porHS256y firma el payload con la clave pública RSA utilizada como secreto HMAC. Si el servidor no controla el algoritmo, acepta el token. Bloquee siempre el algoritmo esperado en el lado del servidor. - Secretos HMAC en duro en el código: un secreto confirmado en un repositorio Git deja sin valor toda la confianza de los tokens. Almacene los secretos en variables de entorno o en un vault aplicativo.
- Clave pública vs clave privada: para verificar un JWT firmado en RSA o ECDSA, se proporciona la clave pública, nunca la privada. La privada solo sirve para firmar y no debe salir nunca del emisor.
- Expiración ignorada: una firma válida sobre un token caducado nunca
debe aceptarse. Recuerde verificar
expynbf. - Audiencia no controlada: un token destinado a la API A no debería ser aceptado
por la API B. Verifique la claim
aud.
Claims temporales: exp y nbf
Más allá de la firma, un JWT válido también debe respetar sus restricciones temporales:
- exp (expiration): el token deja de ser válido después de esa fecha.
- nbf (not before): el token todavía no es válido antes de esa fecha.
Nuestra herramienta señala explícitamente cuando un token está caducado o todavía no es válido, incluso si su firma es correcta. Es importante: una firma válida sobre un token caducado nunca debe aceptarse en producción.
Diferencia con nuestro JWT decoder
Nuestro JWT decoder se limita a decodificar las partes header y payload para hacerlas legibles. No realiza ninguna verificación de firma y no pide clave. Utilícelo para inspeccionar rápidamente el contenido de un token. Utilice el JWT verifier (esta página) en cuanto necesite probar que un token es auténtico. Para fabricar un JWT firmado con fines de prueba, utilice nuestro JWT builder.
Preguntas frecuentes
¿Por qué RS256 en lugar de HS256?
Con HS256, el emisor y el verificador comparten el mismo secreto: por tanto, cualquier verificador puede emitir tokens. Es manejable cuando se controlan ambos extremos. En cuanto se habla de un único proveedor de identidad con varios servicios consumidores, se pasa a RS256: el emisor conserva la clave privada y se distribuye la clave pública a todas las API que deben verificar. Ninguna API consumidora puede entonces forjar tokens.
¿Cómo recuperar la clave pública de un proveedor de identidad (IdP)?
La mayoría de IdP expone un endpoint JWKS estandarizado (por ejemplo
https://exemple.com/.well-known/jwks.json). Ese endpoint devuelve un JSON que contiene
las claves públicas activas. Puede convertir la entrada JWK que corresponde al kid
del header de su JWT en clave PEM mediante el comando openssl o mediante una biblioteca
JWKS de su stack (por ejemplo jose-jwt, jwks-rsa).
¿Qué hacer si el verify falla?
Compruebe primero el algoritmo: un token firmado en HS256 no se verifica con una clave RSA, y
a la inversa. Compruebe después la clave: un carácter en blanco de más, un salto de línea que falte
en una clave PEM o un secreto HMAC ligeramente distinto al utilizado por el emisor
bastan para que la verificación falle. Si el IdP ha rotado la clave, su
kid puede apuntar a una clave que ya no tiene.
¿Qué es un JWKS?
JWKS (JSON Web Key Set, RFC 7517) es un formato JSON que describe un conjunto de
claves públicas. Cada clave se identifica con un kid (key ID) y el JWT que verificar
referencia ese kid en su header. El mecanismo permite al IdP rotar sus
claves sin romper a los verificadores: estos simplemente consultan el endpoint JWKS para recuperar la
clave correspondiente al kid del token recibido.
¿Cómo generar un par de claves RSA para firmar mis JWT?
Con OpenSSL: openssl genrsa -out private.pem 2048 y, después,
openssl rsa -in private.pem -pubout -out public.pem. La clave privada firma en el lado del
emisor, la clave pública verifica en el lado del consumidor. Para nuevos servicios, prefiera 3072 o
4096 bits.
¿Hay que cifrar el JWT además de firmarlo (JWE)?
Un JWT firmado (JWS) garantiza la integridad y la autenticidad, pero el payload sigue siendo legible para quien lo recupere. Si el token contiene datos sensibles (identificadores internos, derechos detallados, datos personales), considere el formato JWE (JSON Web Encryption) que cifra el payload además de firmarlo.
Ejemplo de solicitud
curl -X POST https://cdrn.fr/api/v1/tools/jwt-verifier/execute \
-H "Content-Type: application/json" \
-d '{"token":"...","key":"..."}'
Esquema de entrada
| Campo | Tipo | Obligatorio | Por defecto |
|---|---|---|---|
token |
text | ✓ | – |
key |
text | ✓ | – |
Puntos de acceso
GET https://cdrn.fr/api/v1/tools- lista todas las herramientas disponiblesGET https://cdrn.fr/api/v1/tools/jwt-verifier- recupera el esquema de esta herramientaPOST https://cdrn.fr/api/v1/tools/jwt-verifier/execute- ejecuta esta herramienta con un payload JSON