Cómo funciona un JWT
Un JSON Web Token (RFC 7519) son tres trozos de texto unidos por puntos. La cabecera dice cómo se firma el token, el payload contiene los claims, como quién es el usuario y cuándo caduca el token, y la firma demuestra que ambos los hizo alguien con la clave. La cabecera y el payload son JSON escrito en Base64url, una variante de Base64 que es segura en las URL.
header.payload.signature
header = base64url(UTF-8 JSON, e.g. {"alg":"HS256","typ":"JWT"})
payload = base64url(UTF-8 JSON with the claims)
signature = base64url(HMAC-SHA256(secret, header + "." + payload)) Base64url es una codificación, no un cifrado: cualquiera que tenga un token puede leer su payload, exactamente como hace esta página, sin ninguna clave. Por eso nunca pongas contraseñas ni otros secretos en un JWT. Lo que protege la clave es la firma: cambia un solo carácter del payload y la firma deja de coincidir.
Con HS256, HS384 y HS512, el emisor y el servidor comparten un secreto y firman con HMAC; esta página puede comprobarlos cuando introduces el secreto. RS256, ES256 y los demás algoritmos de clave pública se firman con una clave privada y se comprueban con la clave pública del emisor, que un servidor suele obtener de una URL JWKS. Decodificar un token no es lo mismo que confiar en él: un servidor debe comprobar la firma, la caducidad y la audiencia.
Ejemplo
Toma el conocido ejemplo de jwt.io, eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c. La primera parte se decodifica en la cabecera {"alg":"HS256","typ":"JWT"}: una firma HMAC-SHA256. La segunda, en el payload {"sub":"1234567890","name":"John Doe","iat":1516239022}. Su iat de 1516239022 significa que se emitió el 18 de enero de 2018 a las 01:30:22 UTC, y al no tener exp nunca caduca. La última parte es el HMAC-SHA256 de 32 bytes de las dos primeras partes y del punto que hay entre ellas; con el secreto your-256-bit-secret coincide, así que la firma es válida.
Los claims registrados
| Claim | Qué significa |
|---|---|
iss · Emisor | Quién creó y firmó el token, normalmente la URL del servicio de inicio de sesión. |
sub · Sujeto | De quién trata el token, normalmente un ID de usuario. |
aud · Audiencia | Para quién es el token. Un servidor debe rechazar un token cuya audiencia no sea él mismo. |
exp · Caduca el | Pasado este momento el token debe rechazarse. Segundos desde el 1 de enero de 1970 UTC. |
nbf · No válido antes de | Antes de este momento el token debe rechazarse. Segundos desde el 1 de enero de 1970 UTC. |
iat · Emitido el | Cuándo se creó el token. Segundos desde el 1 de enero de 1970 UTC. |
jti · ID del token | Un ID único de este token, para que un servidor pueda bloquearlo o notar que se usa dos veces. |
Preguntas
¿Es seguro pegar aquí mi JWT?
Sí. El token lo decodifica JavaScript en tu navegador, y la firma se comprueba con la WebCrypto integrada en el navegador. Ni el token ni el secreto se envían a un servidor ni se guardan. Aun así, trata un token en uso como una contraseña: quien lo tenga puede usarlo hasta que caduque.
¿Se puede decodificar un JWT sin el secreto?
Sí. La cabecera y el payload son solo JSON codificado en Base64url, así que cualquiera puede leerlos sin clave. El secreto o la clave pública solo hacen falta para comprobar que la firma es auténtica. Por eso un JWT no debe contener contraseñas ni otros secretos.
¿Cómo compruebo si un JWT ha caducado?
Mira el claim exp: es la hora de caducidad en segundos desde el 1 de enero de 1970 UTC. Si la hora actual la ha pasado, el token ha caducado. Esta página lee exp y nbf por ti y muestra el resultado como fecha y como «caducó hace 3 días» o «caduca dentro de 2 horas».
¿Qué diferencia hay entre HS256 y RS256?
HS256 firma con HMAC y un único secreto compartido: quien puede comprobar un token también puede crear uno. RS256 firma con una clave privada RSA y se comprueba con la clave pública, así que los servicios pueden verificar tokens sin poder emitirlos. RS256 o ES256 es la opción habitual cuando varios servicios comprueban los mismos tokens.
¿Por qué la firma de mi JWT no es válida?
El secreto es incorrecto, está codificado en Base64 y necesita la opción «El secreto está codificado en Base64», o el token se cambió después de firmarlo. Al copiar un token también se pueden añadir o perder caracteres. Si el token usa RS256, ES256 u otro algoritmo de clave pública, no se puede comprobar con un secreto: necesita la clave pública del emisor.