Un JSON Web Token, RFC 7519, es una forma compacta de transportar un conjunto de afirmaciones de
una parte a otra para que la parte receptora pueda confiar en quien las envio, o al
menos verificar que nada cambio en transito. Cada JWT que veras en
un encabezado Authorization: Bearer son las mismas tres piezas unidas por puntos:
header.payload.signature.
Las tres partes
El encabezado y la carga util son cada uno un objeto JSON, codificado en base64url. El
encabezado nombra el algoritmo de firma y el tipo de token, tipicamente algo
tan pequeno como {"alg":"HS256","typ":"JWT"}. La carga util contiene las afirmaciones: los
datos que el token realmente transporta, mas un puñado de nombres registrados con
significados definidos, iss (emisor), sub (sujeto), aud (audiencia), iat
(fecha de emision), nbf (no antes de) y exp (expiracion) y jti (un id de token). Ninguno
de eso es requerido por la especificacion mas alla de lo que el emisor elija incluir,
por lo que dos JWTs de dos servicios diferentes pueden transportar afirmaciones completamente
diferentes.
La firma no es JSON en absoluto. Es el resultado de ejecutar el encabezado y
la carga util, todavia en su forma codificada, a traves del algoritmo nombrado en el
encabezado, siendo HS256 (HMAC con un secreto compartido) y RS256/ES256 (RSA o
ECDSA con una clave privada) los que encontraras con mas frecuencia. Decodificar la firma en base64url
te da bytes sin ninguna estructura adicional para leer.
Codificado no es encriptado
Base64url es una codificacion, no un cifrado. Cualquiera que tenga un JWT puede decodificar el encabezado y la carga util con nada mas que un editor de texto, que es exactamente lo que hace el Decodificador JWT. Eso significa que un JWT nunca es el lugar correcto para cualquier cosa que no pondrias en una URL: una contrasena, un numero de tarjeta de credito, un nombre completo que alguien no ha aceptado exponer. Si una carga util necesita mantenerse confidencial en lugar de solo a prueba de manipulaciones, eso requiere un token de Encripcion Web JSON, un formato diferente y menos comun, no un JWT firmado con un algoritmo mas fuerte.
Decodificar no dice nada sobre la confianza
Esta es la parte por la que mas se culpa a los decodificadores, por lo que vale la pena decirlo claramente: leer las afirmaciones de un JWT no prueba nada sobre si el token es genuino. Verificar una firma significa recalcularla con el secreto real o la clave publica con la que fue firmado el token y verificar que coincida, byte por byte. Un decodificador que solo divide el token en sus puntos y decodifica en base64url dos de las tres partes, que es lo que hace todo decodificador puro del lado del cliente, no tiene acceso a esa clave y no puede hacer esa verificacion. Puede decirte que afirma un token. No puede decirte si debes creerle.
Un token bien formado, que se decodifica limpiamente, puede ser falsificado, expirado, o
firmado con una clave que nunca fue emitida para el. exp y nbf valen la pena
verificarlos en cada decodificacion por exactamente esta razon: un token que paso su
expiracion, o que todavia no es valido, es invalido sin importar si su firma
es correcta, y leer esos dos campos como las marcas de tiempo que representan
en lugar de numeros crudos es la forma mas rapida de detectarlo de un vistazo.
Para que sirve esto
A pesar de esa limitacion, decodificar sin verificar tiene usos reales, diarios: leer que alcances fueron emitidos con un token de acceso mientras se depura una integracion de API, verificar si el token que tu aplicacion acaba de recibir realmente expiro (en lugar de adivinar a partir de un vago 401), o inspeccionar que contiene el token de un tercero antes de decidir si tu servicio necesita confiar en el en absoluto. Nada de eso requiere la clave de firma, solo el token en si.
Pega uno en el Decodificador JWT y separa el encabezado, las afirmaciones registradas y la carga util restante en sus propias filas, marca inmediatamente un token expirado o que todavia no es valido, y muestra los bytes crudos de la firma sin pretender haberlos verificado contra nada.