jwtk/jjwt · error · UnsupportedJwtException
The parsed JWT indicates it was signed with the '${algId}' s
Error message
The parsed JWT indicates it was signed with the '${algId}' signature algorithm, but the provided ${key.getClass().getName()} key may not be used to verify ${algId} signatures. Because the specified key reflects a specific and expected algorithm, and the JWT does not reflect this algorithm, it is likely that the JWT was not expected and therefore should not be trusted. Another possibility is that the parser was provided the incorrect signature verification key, but this cannot be assumed for security reasons. What it means
After resolving the verification key, the parser validates that the key's algorithm is compatible with the JWS header's 'alg'. When the key reflects a specific expected algorithm that does not match the token's alg, verification is aborted with UnsupportedJwtException as a security measure against algorithm-confusion attacks.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:354
VerifySecureDigestRequest<Key> request =
new DefaultVerifySecureDigestRequest<>(verificationInput, provider, null, key, signature);
if (!algorithm.verify(request)) {
String msg = "JWT signature does not match locally computed signature. JWT validity cannot be " +
"asserted and should not be trusted.";
throw new SignatureException(msg);
}
} catch (WeakKeyException e) {
throw e;
} catch (InvalidKeyException | IllegalArgumentException e) {
String algId = algorithm.getId();
String msg = "The parsed JWT indicates it was signed with the '" + algId + "' signature " +
"algorithm, but the provided " + key.getClass().getName() + " key may " +
"not be used to verify " + algId + " signatures. Because the specified " +
"key reflects a specific and expected algorithm, and the JWT does not reflect " +
"this algorithm, it is likely that the JWT was not expected and therefore should not be " +
"trusted. Another possibility is that the parser was provided the incorrect " +
"signature verification key, but this cannot be assumed for security reasons.";
throw new UnsupportedJwtException(msg, e);
} finally {
Streams.reset(payloadStream);
}
return signature;
}
@Override
public Jwt<?, ?> parse(Reader reader) {
Assert.notNull(reader, "Reader cannot be null.");
return parse(reader, Payload.EMPTY);
}
private Jwt<?, ?> parse(Reader compact, Payload unencodedPayload) {
Assert.notNull(compact, "Compact reader cannot be null.");
Assert.stateNotNull(unencodedPayload, "internal error: unencodedPayload is null.");
View on GitHub (pinned to fb71496164)
Solutions
- Ensure the verification key type matches the token's alg (RSA key for RS*, EC key for ES*, SecretKey for HS*) and that the issuer signs with the same algorithm
- Pin the expected algorithm in the parser (e.g. requireJwsAlgorithm or sig().add(expectedAlg)) so mismatched algs are rejected cleanly
- Never verify HMAC with raw public-key bytes; always use the correct key class
Example fix
// before
Jws<Claims> jws = Jwts.parser()
.verifyWith(publicKeyBytesAsSecretKey)
.build().parseSignedClaims(token); // alg=RS256 vs HMAC key
// after
Jws<Claims> jws = Jwts.parser()
.verifyWith(rsaPublicKey)
.build().parseSignedClaims(token); Defensive patterns
Strategy: try-catch
Try / catch
try {
return parser.parseSignedClaims(token);
} catch (UnsupportedJwtException e) {
if (e.getMessage().contains("may not be used to verify")) {
log.warn("JWT alg does not match verification key algorithm");
}
throw new UnauthorizedException(e);
} Prevention
- Match key type to algorithm family (SecretKey=HS*, PublicKey RSA=RS*, EC=ES*)
- Never feed RSA public key bytes into an HMAC key
- Pin allowed algorithms in the parser configuration
When it happens
Trigger: Token's 'alg' header (e.g. RS256 or attacker-changed alg) does not match the algorithm expected by the provided key (e.g. an HMAC SecretKey when the header says RS256, or an EC key for an RSA alg).
Common situations: Algorithm-confusion attempts where 'alg' was changed from RS256 to HS256 while an RSA public key bytes are used as an HMAC secret; parsers given the wrong key type for the token family; tokens re-signed by a different service with a different algorithm.
Related errors
- JWT signature does not match locally computed signature. JWT
- Unsecured JWSs (those with an alg header value of 'none') ar
- PrivateKeys may not be used to verify digital signatures. Pr
- 'unsecuredDecompression' is only relevant if 'unsecured' is
- Invalid ECDSA signature format.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/0aa3ef25a9703153.
Report an issue: GitHub.