jwtk/jjwt · error · InvalidKeyException

signing keys must be PrivateKey instances.

Error message

${familyName} signing keys must be PrivateKey instances.

What it means

Type guard in SignatureAlgorithm.assertValid for the asymmetric branch (EC or RSA): when signing, the key must be a java.security.PrivateKey, since signing requires private-key material. A PublicKey, SecretKey, or other Key subtype supplied for signing with an ES*/RS*/PS* algorithm triggers InvalidKeyException.

Solutions

  1. Pass the PrivateKey from a KeyPair for signing; obtain one via Keys.keyPairFor(SignatureAlgorithm.RS256/ES256 etc.).
  2. If only a public key is available, the operation should be signature verification, not signing — use assertValidVerificationKey or the parser side.
  3. Load the private key from a keystore/PKCS8 file rather than reusing a certificate's public key.
Defensive patterns

Strategy: type-guard

When it happens

Trigger: Thrown at api/src/main/java/io/jsonwebtoken/SignatureAlgorithm.java:406 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at api/src/main/java/io/jsonwebtoken/SignatureAlgorithm.java:406

                            "size >= " + minKeyLength + " bits (the key size must be greater than or equal to the hash " +
                            "output size).  Consider using the " + Keys.class.getName() + " class's " +
                            "'secretKeyFor(SignatureAlgorithm." + name() + ")' method to create a key guaranteed to be " +
                            "secure enough for " + name() + ".  See " +
                            "https://tools.ietf.org/html/rfc7518#section-3.2 for more information.";
                    throw new WeakKeyException(msg);
                }
            } finally {
                if (encoded != null) {
                    Arrays.fill(encoded, (byte) 0);
                }
            }

        } else { //EC or RSA

            if (signing) {
                if (!(key instanceof PrivateKey)) {
                    String msg = familyName + " signing keys must be PrivateKey instances.";
                    throw new InvalidKeyException(msg);
                }
            }

            if (isEllipticCurve()) {

                if (!(key instanceof ECKey)) {
                    String msg = familyName + " " + keyType(signing) + " keys must be ECKey instances.";
                    throw new InvalidKeyException(msg);
                }

                ECKey ecKey = (ECKey) key;
                int size = ecKey.getParams().getOrder().bitLength();
                if (size < this.minKeyLength) {
                    String msg = "The " + keyType(signing) + " key's size (ECParameterSpec order) is " + size +
                            " bits which is not secure enough for the " + name() + " algorithm.  The JWT " +
                            "JWA Specification (RFC 7518, Section 3.4) states that keys used with " +
                            name() + " MUST have a size >= " + this.minKeyLength +
                            " bits.  Consider using the " + Keys.class.getName() + " class's " +

View on GitHub (pinned to fb71496164)