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

  1. Check e.getCause() for the underlying provider failure.
  2. Confirm the verification algorithm exists on the runtime JVM/provider.
  3. Ensure the verifying PublicKey corresponds to the signing PrivateKey and kty.
  4. 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

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


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/a53f714aac24070f. Report an issue: GitHub.