jwtk/jjwt · error · SignatureException
Unable to verify ${getId()} signature with JCA algorithm '${
Error message
Unable to verify ${getId()} signature with JCA algorithm '${getJcaName()}' using key {${key}}: ${e.getMessage()} What it means
AbstractSecureDigestAlgorithm.verify catches unexpected exceptions from the underlying JCA verification and wraps them in SignatureException, identifying the algorithm id, JCA name, key, and cause message. Like digest, SignatureException/KeyException pass through unmodified.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithm.java:74
}
protected abstract byte[] doDigest(SecureRequest<InputStream, S> request) throws Exception;
@Override
public final boolean verify(VerifySecureDigestRequest<V> request) throws SecurityException {
Assert.notNull(request, "Request cannot be null.");
final V key = Assert.notNull(request.getKey(), "Verification key cannot be null.");
Assert.notNull(request.getPayload(), "Request content cannot be null or empty.");
Assert.notEmpty(request.getDigest(), "Request signature byte array cannot be null or empty.");
try {
validateKey(key, false);
return doVerify(request);
} catch (SignatureException | KeyException e) {
throw e; //propagate
} catch (Exception e) {
String msg = "Unable to verify " + getId() + " signature with JCA algorithm '" + getJcaName() + "' " +
"using key {" + KeysBridge.toString(key) + "}: " + e.getMessage();
throw new SignatureException(msg, e);
}
}
protected abstract boolean doVerify(VerifySecureDigestRequest<V> request);
}
View on GitHub (pinned to fb71496164)
Solutions
- Check e.getCause() for the underlying provider failure.
- Confirm the verification algorithm exists on the runtime JVM/provider.
- Ensure the verifying PublicKey corresponds to the signing PrivateKey and kty.
- Install a provider such as BouncyCastle for algorithms absent from the default set.
Example fix
// before
boolean ok = alg.verify(req); // SignatureException: Unable to verify ES256 ...
// after
try { boolean ok = alg.verify(req); }
catch (SignatureException e) { throw new GeneralSecurityException(e.getCause()); } Defensive patterns
Strategy: try-catch
Validate before calling
try { Signature.getInstance(alg.getJcaName()); } catch (NoSuchAlgorithmException e) { /* unavailable */ } Type guard
boolean canVerify(Key k) { return k instanceof PublicKey || k instanceof SecretKey; } Try / catch
try { boolean ok = alg.verify(req); }
catch (SignatureException e) { return VerificationResult.error(e.getCause()); } Prevention
- Ensure the public key corresponds to the signer's private key.
- Check provider availability at startup, not per-request.
- Avoid reusing Signature instances across threads.
When it happens
Trigger: Verifying a signature where the JCA layer fails: provider lacks the algorithm, key type/provider mismatch, or bad internal state on the Signature instance.
Common situations: Verifying EdDSA or RS256 signatures on a JDK without the algorithm; using a public key from a different key pair family; hardware/provider keys not initialized.
Related errors
- Unable to compute ${getId()} signature with JCA algorithm '$
- ${getId()} ${keyType(signing)} keys must be ${type.getSimple
- Unrecognized EC key algorithm name.
- Invalid ECDSA signature format.
- Unexpected unsecured Claims JWT.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/a53f714aac24070f.
Report an issue: GitHub.