jwtk/jjwt · error · InvalidKeyException

JWS verification key must be either a SecretKey (for MAC alg

Error message

JWS verification key must be either a SecretKey (for MAC algorithms) or a PublicKey (for Signature algorithms).

What it means

Thrown as InvalidKeyException from DefaultJwtParserBuilder.setSigningKey(Key) when the key is neither a SecretKey (for HMAC/MAC algorithms) nor a PublicKey (for asymmetric signature verification) — e.g. a PrivateKey, or an arbitrary Key implementation. Deprecated in favor of verifyWith(...).

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java:264

    }

    @Override
    public JwtParserBuilder setSigningKey(String base64EncodedSecretKey) {
        Assert.hasText(base64EncodedSecretKey, "signature verification key cannot be null or empty.");
        byte[] bytes = Decoders.BASE64.decode(base64EncodedSecretKey);
        return setSigningKey(bytes);
    }

    @Override
    public JwtParserBuilder setSigningKey(final Key key) {
        if (key instanceof SecretKey) {
            return verifyWith((SecretKey) key);
        } else if (key instanceof PublicKey) {
            return verifyWith((PublicKey) key);
        }
        String msg = "JWS verification key must be either a SecretKey (for MAC algorithms) or a PublicKey " +
                "(for Signature algorithms).";
        throw new InvalidKeyException(msg);
    }

    @Override
    public JwtParserBuilder verifyWith(SecretKey key) {
        return verifyWith((Key) key);
    }

    @Override
    public JwtParserBuilder verifyWith(PublicKey key) {
        return verifyWith((Key) key);
    }

    private JwtParserBuilder verifyWith(Key key) {
        if (key instanceof PrivateKey) {
            throw new IllegalArgumentException(DefaultJwtParser.PRIV_KEY_VERIFY_MSG);
        }
        this.signatureVerificationKey = Assert.notNull(key, "signature verification key cannot be null.");
        return this;

View on GitHub (pinned to fb71496164)

Solutions

  1. For asymmetric tokens, pass the corresponding PublicKey: .verifyWith(publicKey).
  2. For HMAC tokens, wrap raw bytes in a SecretKeySpec: new SecretKeySpec(bytes, "HmacSHA256") and pass it.
  3. Migrate from the deprecated setSigningKey to verifyWith(Key), which gives clearer errors.
  4. Check which algorithm family the token uses (alg header) to know whether a SecretKey or PublicKey is required.

Example fix

// before
PrivateKey privateKey = loadPrivateKey();
Jwts.parser().setSigningKey(privateKey).build().parse(jwt); // InvalidKeyException
// after
PublicKey publicKey = loadPublicKey(); // matching public key
Jwts.parser().verifyWith(publicKey).build().parse(jwt);
// or for MAC: Jwts.parser().verifyWith(new SecretKeySpec(secretBytes, "HmacSHA256")).build()
Defensive patterns

Strategy: type-guard

Validate before calling

boolean isUsableVerificationKey(java.security.Key k) {
    return k instanceof javax.crypto.SecretKey || k instanceof java.security.PublicKey;
}
if (!isUsableVerificationKey(key)) throw new IllegalArgumentException("Need SecretKey or PublicKey");

Type guard

boolean isVerificationKey(java.security.Key k) {
    return k instanceof javax.crypto.SecretKey || k instanceof java.security.PublicKey;
}

Try / catch

try {
    parserBuilder.setSigningKey(key);
} catch (io.jsonwebtoken.security.InvalidKeyException e) {
    // wrong key type: select PublicKey for RSA/EC tokens or SecretKeySpec for MAC
}

Prevention

When it happens

Trigger: parserBuilder.setSigningKey(key) where key is a PrivateKey (loaded from a keystore for signing), a raw byte array wrapper that isn't a SecretKey, or null/unsupported Key type.

Common situations: Developers reusing the same key object they used to sign (a PrivateKey) for verification instead of the corresponding PublicKey; passing raw byte[] instead of constructing a SecretKeySpec; confusion after migrating between MAC and RSA/EC tokens.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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