jwtk/jjwt · error · InvalidKeyException

MAC ${keyType} keys must be SecretKey instances. Specified

Error message

MAC ${keyType} keys must be SecretKey instances.  Specified key is of type ${k.getClass().getName()}

What it means

InvalidKeyException from DefaultMacAlgorithm.validateKey when the supplied Key is not a javax.crypto.SecretKey instance. MAC (HMAC) algorithms require symmetric secret keys, not RSA/EC public or private keys.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java:161

        if (!generic && isJwaStandard() && !isJwaStandardJcaName(name)) {
            throw new InvalidKeyException("The " + keyType(signing) + " key's algorithm '" + name +
                    "' does not equal a valid HmacSHA* algorithm name or PKCS12 OID and cannot be used with " +
                    getId() + ".");
        }
    }

    @Override
    protected void validateKey(Key k, boolean signing) {

        final String keyType = keyType(signing);
        if (k == null) {
            throw new IllegalArgumentException("MAC " + keyType + " key cannot be null.");
        }

        if (!(k instanceof SecretKey)) {
            String msg = "MAC " + keyType + " keys must be SecretKey instances.  Specified key is of type " +
                    k.getClass().getName();
            throw new InvalidKeyException(msg);
        }

        if (k instanceof Password) {
            String msg = "Passwords are intended for use with key derivation algorithms only.";
            throw new InvalidKeyException(msg);
        }

        final SecretKey key = (SecretKey) k;

        final String id = getId();

        assertAlgorithmName(key, signing);

        int size = KeysBridge.findBitLength(key);

        // We can only perform length validation if key bit length is available
        // per https://github.com/jwtk/jjwt/issues/478 and https://github.com/jwtk/jjwt/issues/619
        // so return early if we can't:

View on GitHub (pinned to fb71496164)

Solutions

  1. Use a SecretKey: Keys.hmacShaKeyFor(secretBytes) or Jwts.SIG.HS256.key().build().
  2. If you have an RSA/EC key pair, switch to the matching asymmetric algorithm (RS256/ES256) instead of HS256.
  3. Check the keystore lookup so you retrieve the intended secret-key entry.
  4. Guard with (key instanceof SecretKey) before calling signWith/verifyWith.

Example fix

// before
KeyPair kp = Keys.keyPairFor(SignatureAlgorithm.RS256);
Jwts.builder().signWith(kp.getPrivate(), Jwts.SIG.HS256); // wrong key type
// after
SecretKey key = Keys.hmacShaKeyFor(secretBytes);
Jwts.builder().signWith(key, Jwts.SIG.HS256);
Defensive patterns

Strategy: type-guard

Validate before calling

static SecretKey requireSecretKey(Key k) {
    if (!(k instanceof SecretKey))
        throw new IllegalArgumentException("HMAC requires a SecretKey, got " + k.getClass().getName());
    return (SecretKey) k;
}

Type guard

boolean isSecretKey(Key k) { return k instanceof javax.crypto.SecretKey; }

Try / catch

try {
    return Jwts.builder().signWith(key, Jwts.SIG.HS256).compact();
} catch (InvalidKeyException e) {
    if (e.getMessage().contains("SecretKey instances"))
        throw new IllegalStateException("Asymmetric key used with MAC algorithm");
    throw e;
}

Prevention

When it happens

Trigger: Calling signWith(rsaPrivateKey, HS256) or verifyWith(ecPublicKey) with an HMAC algorithm; passing a java.security.Key from a keystore that is a PrivateKey.

Common situations: Mixing asymmetric signing code (RS256) with HMAC algorithm configuration; loading the wrong key entry from a keystore; copy-pasting algorithm constants while reusing key variables.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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