Fehlermeldung
JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
Auch ausgegeben als
- 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
Was der Fehler bedeutet
JJWT hat die Signatur über Header und Payload des Tokens mit dem von dir konfigurierten Schlüssel neu berechnet (HMAC) oder geprüft (RSA, ECDSA, EdDSA), und sie passte nicht zum Signatursegment des Tokens. Das Token ließ sich problemlos parsen, und der Algorithmus passte zum Schlüssel; Schlüssel und Token gehören einfach nicht zusammen, oder das Token wurde nach dem Signieren verändert.
Warum der Fehler auftritt
Die prüfende Seite verwendet einen anderen Schlüssel
häufigDer Schlüssel einer anderen Umgebung, ein beim Start neu erzeugtes Schlüsselpaar (ein häufiger Bug in Demos, die in die Produktion übernommen wurden) oder eine einzelne Dienstinstanz mit einem veralteten Secret.
Gleiches HMAC-Secret, andere Bytes
häufigEine Seite verwendet die UTF-8-Bytes des Strings, die andere dekodiert ihn zuerst aus base64 (die Beispiele von Spring speichern Secrets oft base64-kodiert). In der Konfiguration sehen die Secrets identisch aus und erzeugen doch unterschiedliche MACs.
Schlüsselrotation ohne Behandlung von kid
gelegentlichDer Aussteller signiert mit einem neuen Schlüssel, während die prüfende Seite noch immer nur den alten hat. Ohne einen Key Locator, der Schlüssel anhand von `kid` auswählt, kann die prüfende Seite nicht einmal erkennen, welcher Schlüssel gemeint war.
Das Token wurde verändert
gelegentlichJede Änderung am Header- oder Payload-Segment – auch an Whitespace oder durch erneutes Kodieren – macht die Signatur ungültig.
So behebst du den Fehler
- 1.
Schlüssel mit einem Key Locator anhand von kid auflösen
JJWT 0.12+ unterstützt `keyLocator`, der den Header erhält und den passenden Schlüssel zurückgibt. Kombiniere ihn mit einem JWKS, das du bei einer Rotation aktualisierst.
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.
Sich auf die Bytes des HMAC-Schlüssels einigen
Leg fest, ob das konfigurierte Secret Text oder base64 ist, und leite den Schlüssel auf jeder Seite auf dieselbe Weise ab. Der HMAC-Rechner zeigt den MAC für beide Interpretationen.
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")));