jwtk/jjwt · error · IllegalArgumentException

The algorithm does not support Key Pairs.

Error message

The  algorithm does not support Key Pairs.

What it means

Deprecated Keys.keyPairFor(SignatureAlgorithm) throws IllegalArgumentException when the given algorithm is not an asymmetric signature algorithm, i.e. an HMAC algorithm like HS256 was requested as a KeyPair. MAC algorithms have no public/private pair.

Solutions

  1. Only call keyPairFor with asymmetric algorithms: RS256/RS384/RS512, PS256..PS512, ES256/ES384/ES512, EdDSA
  2. Use Keys.secretKeyFor(alg) or Jwts.SIG.HS256.key().build() for HMAC algorithms
  3. Guard with a check: if the algorithm name starts with "HS", generate a secret key instead
  4. Migrate to Jwts.SIG.<Alg>.keyPair().build() modern builder API

Example fix

// before
KeyPair kp = Keys.keyPairFor(SignatureAlgorithm.HS256); // throws
// after
SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); // HMAC has no keypair
KeyPair kp = Keys.keyPairFor(SignatureAlgorithm.RS256); // asymmetric path
Defensive patterns

Strategy: type-guard

Validate before calling

if (alg.name().startsWith("HS")) throw new IllegalArgumentException(alg + " is HMAC; use secretKeyFor");

Type guard

static boolean isAsymmetric(io.jsonwebtoken.SignatureAlgorithm alg) {
    return alg != null && !alg.name().startsWith("HS");
}

Try / catch

try {
    KeyPair kp = Keys.keyPairFor(alg);
} catch (IllegalArgumentException e) {
    SecretKey sk = Keys.secretKeyFor(alg); // fall back to symmetric generation
}

Prevention

When it happens

Trigger: Calling Keys.keyPairFor(SignatureAlgorithm.HS256) (or HS384/HS512) — the resolved SecureDigestAlgorithm is a MacAlgorithm, not the (new) SignatureAlgorithm interface, so key pair creation is rejected.

Common situations: Generic code that generates a key pair for any SignatureAlgorithm value; mixing HMAC and asymmetric algorithm constants; migration to 0.12.x where Jwts.SIG instances are used.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


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

Appendix: source

Thrown at api/src/main/java/io/jsonwebtoken/security/Keys.java:250

     * <td>{@code secp521r1}</td>
     * </tr>
     * </table>
     *
     * @param alg the {@code SignatureAlgorithm} to inspect to determine which asymmetric algorithm to use.
     * @return a new {@link KeyPair} suitable for use with the specified asymmetric algorithm.
     * @throws IllegalArgumentException if {@code alg} is not an asymmetric algorithm
     * @deprecated since 0.12.0 in favor of your preferred
     * {@link io.jsonwebtoken.security.SignatureAlgorithm} instance's
     * {@link SignatureAlgorithm#keyPair() keyPair()} builder method directly.
     */
    @SuppressWarnings("DeprecatedIsStillUsed")
    @Deprecated
    public static KeyPair keyPairFor(io.jsonwebtoken.SignatureAlgorithm alg) throws IllegalArgumentException {
        Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
        SecureDigestAlgorithm<?, ?> salg = Jwts.SIG.get().get(alg.name());
        if (!(salg instanceof SignatureAlgorithm)) {
            String msg = "The " + alg.name() + " algorithm does not support Key Pairs.";
            throw new IllegalArgumentException(msg);
        }
        SignatureAlgorithm asalg = ((SignatureAlgorithm) salg);
        return asalg.keyPair().build();
    }

    /**
     * Returns a new {@link Password} instance suitable for use with password-based key derivation algorithms.
     *
     * <p><b>Usage Note</b>: Using {@code Password}s outside of key derivation contexts will likely
     * fail. See the {@link Password} JavaDoc for more, and also note the <b>Password Safety</b> section below.</p>
     *
     * <p><b>Password Safety</b></p>
     *
     * <p>Instances returned by this method use a <em>clone</em> of the specified {@code password} character array
     * argument - changes to the argument array will NOT be reflected in the returned key, and vice versa.  If you wish
     * to clear a {@code Password} instance to ensure it is no longer usable, call its {@link Password#destroy()}
     * method will clear/overwrite its internal cloned char array. Also note that each subsequent call to
     * {@link Password#toCharArray()} will also return a new clone of the underlying password character array per

View on GitHub (pinned to fb71496164)