Message d’erreur
JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
Également affiché sous la forme
- io.jsonwebtoken.security.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
JJWT (Java) — io.jsonwebtoken.security.SignatureException from JwtParser.parseSignedClaims
Ce que cela signifie
JJWT a recalculé (HMAC) ou vérifié (RSA, ECDSA, EdDSA) la signature de l’en-tête et de la charge utile du jeton avec la clé que vous avez configurée, et elle ne correspond pas au segment de signature du jeton. Le jeton a été analysé sans problème et l’algorithme convenait à la clé : la clé et le jeton ne vont simplement pas ensemble, ou le jeton a été modifié après la signature.
Pourquoi cela se produit
Le vérificateur utilise une autre clé
fréquenteLa clé d’un autre environnement, une paire de clés régénérée au démarrage (un bug courant dans les démos passées en production) ou une instance de service dotée d’un secret périmé.
Même secret HMAC, octets différents
fréquenteUn côté utilise les octets UTF-8 de la chaîne, l’autre la décode d’abord depuis le base64 (les exemples de Spring stockent souvent des secrets en base64). Les secrets semblent identiques dans la configuration et produisent des MAC différents.
Rotation des clés sans gestion du kid
occasionnelleL’émetteur signe avec une nouvelle clé alors que le vérificateur ne dispose encore que de l’ancienne. Sans localisateur de clés indexé par `kid`, le vérificateur ne peut même pas savoir de quelle clé il s’agit.
Le jeton a été modifié
occasionnelleToute modification du segment d’en-tête ou de charge utile, y compris des espaces ou un nouvel encodage, invalide la signature.
Comment corriger l’erreur
- 1.
Résoudre les clés par kid avec un localisateur de clés
JJWT 0.12+ prend en charge `keyLocator`, qui reçoit l’en-tête et renvoie la bonne clé. Associez-le à un JWKS que vous actualisez à chaque rotation.
java import io.jsonwebtoken.*; import java.security.Key; // Pick the verification key by the token's kid instead of a single static key. Locator<Key> keys = new LocatorAdapter<>() { @Override protected Key locate(JwsHeader header) { Key key = publicKeysByKid.get(header.getKeyId()); // refreshed from the issuer's JWKS if (key == null) throw new UnsupportedJwtException("unknown kid " + header.getKeyId()); return key; } }; Jws<Claims> jws = Jwts.parser().keyLocator(keys).requireIssuer("https://issuer.example.com/").build().parseSignedClaims(token); - 2.
S’accorder sur les octets de la clé HMAC
Décidez si le secret configuré est du texte ou du base64 et dérivez la clé de la même manière de chaque côté. Le calculateur HMAC affiche le MAC pour les deux interprétations.
java // Both sides must derive the same key bytes. If the secret is stored base64-encoded, decode it. javax.crypto.SecretKey key = io.jsonwebtoken.security.Keys.hmacShaKeyFor( java.util.Base64.getDecoder().decode(System.getenv("JWT_SECRET_B64")));