Skip to content
ecdsa.com
JJWT (Java)Java

Error message

JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.

Also printed as

  • 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

What it means

JJWT recomputed (HMAC) or verified (RSA, ECDSA, EdDSA) the signature over the token's header and payload with the key you configured, and it did not match the token's signature segment. The token parsed fine and the algorithm fit the key; the key and the token simply do not belong together, or the token changed after signing.

Why it happens

How to fix it

  1. 1.

    Resolve keys by kid with a key locator

    JJWT 0.12+ supports `keyLocator`, which receives the header and returns the right key. Combine it with a JWKS that you refresh on 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. 2.

    Agree on the HMAC key bytes

    Decide whether the configured secret is text or base64 and derive the key the same way on every side. The HMAC calculator shows the MAC for both interpretations.

    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")));

Related errors

Browse the full signature error database