jwtk/jjwt · error · IllegalArgumentException
PrivateKeys may not be used to encrypt data. PublicKeys are
Error message
PrivateKeys may not be used to encrypt data. PublicKeys are used to encrypt, and PrivateKeys are used to decrypt.
What it means
For JWE encryption, data is encrypted with the recipient's PublicKey (asymmetric key management) — PrivateKeys decrypt. Encrypting with a PrivateKey is cryptographically incorrect, so encryptWith rejects it with an IllegalArgumentException.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java:296
return signWith(key, alg);
}
@Override
public JwtBuilder encryptWith(SecretKey key, AeadAlgorithm enc) {
if (key instanceof Password) {
return encryptWith((Password) key, new Pbes2HsAkwAlgorithm(enc.getKeyBitLength()), enc);
}
return encryptWith(key, Jwts.KEY.DIRECT, enc);
}
@Override
public <K extends Key> JwtBuilder encryptWith(final K key, final KeyAlgorithm<? super K, ?> keyAlg, final AeadAlgorithm enc) {
this.enc = Assert.notNull(enc, "Encryption algorithm cannot be null.");
Assert.hasText(enc.getId(), "Encryption algorithm id cannot be null or empty.");
Assert.notNull(key, "Encryption key cannot be null.");
if (key instanceof PrivateKey) {
throw new IllegalArgumentException(PRIV_KEY_ENC_MSG);
}
Assert.notNull(keyAlg, "KeyAlgorithm cannot be null.");
final String algId = Assert.hasText(keyAlg.getId(), "KeyAlgorithm id cannot be null or empty.");
this.key = key;
//noinspection unchecked
this.keyAlg = (KeyAlgorithm<Key, ?>) keyAlg;
final KeyAlgorithm<Key, ?> alg = this.keyAlg;
final String cekMsg = "Unable to obtain content encryption key from key management algorithm '%s'.";
this.keyAlgFunction = Functions.wrap(alg::getEncryptionKey, SecurityException.class, cekMsg, algId);
return this;
}
@Override
public JwtBuilder compressWith(CompressionAlgorithm alg) {
Assert.notNull(alg, "CompressionAlgorithm cannot be null");View on GitHub (pinned to fb71496164)
Solutions
- Pass the recipient's PublicKey to encryptWith; keep the PrivateKey only for decryption on the recipient side.
- Add a guard: if (key instanceof PrivateKey) throw/redirect to the correct key before calling the builder.
- Fix configuration/keystore lookup so encryption code receives public keys.
- Catch IllegalArgumentException and log a key-role configuration error.
Example fix
// before builder.encryptWith(myPrivateKey, Jwts.KEY.RSA_OAEP, Jwts ENC.A256GCM); // after builder.encryptWith(recipientPublicKey, Jwts.KEY.RSA_OAEP, Jwts.ENC.A256GCM);
Defensive patterns
Strategy: validation
Validate before calling
if (key instanceof PrivateKey) throw new IllegalArgumentException("encryptWith requires a PublicKey"); Type guard
boolean canEncrypt(Key k) { return !(k instanceof PrivateKey) && k != null; } Try / catch
try { builder.encryptWith(key, keyAlg, enc); } catch (IllegalArgumentException e) { /* wrong key role */ } Prevention
- Encrypt with the recipient's PublicKey; decrypt only with the PrivateKey
- Type helper parameters as PublicKey for encryption APIs
- Verify keystore aliases resolve to keys with the expected role
When it happens
Trigger: JwtBuilder.encryptWith(privateKey, keyAlg, enc) where the key argument is a java.security.PrivateKey.
Common situations: Reusing the signing (private) key object in the encryption call; mixing up encrypt/decrypt sides of an asymmetric JWE flow; keystore alias loading the wrong entry.
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
- PublicKeys may not be used to decrypt data. PublicKeys are u
- Unexpected content JWE.
- Unexpected Claims JWE.
- PublicKeys may not be used to create digital signatures. Pri
- Payload encoding may not be disabled for s, only JWSs.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/979051e397dd6941.
Report an issue: GitHub.