jwtk/jjwt · error · IllegalArgumentException
PublicKeys may not be used to create digital signatures. Pri
Error message
PublicKeys may not be used to create digital signatures. PrivateKeys are used to sign, and PublicKeys are used to verify.
What it means
Digital signatures are created with PrivateKeys and verified with PublicKeys. Passing a PublicKey to signWith would be cryptographically wrong, so the builder rejects it immediately with an IllegalArgumentException.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java:217
throw new UnsupportedKeyException(msg);
}
return alg;
}
@Override
public JwtBuilder signWith(Key key) throws InvalidKeyException {
Assert.notNull(key, "Key argument cannot be null.");
SecureDigestAlgorithm<Key, ?> alg = forSigningKey(key); // https://github.com/jwtk/jjwt/issues/381
return signWith(key, alg);
}
@Override
public <K extends Key> JwtBuilder signWith(K key, final SecureDigestAlgorithm<? super K, ?> alg)
throws InvalidKeyException {
Assert.notNull(key, "Key argument cannot be null.");
if (key instanceof PublicKey) { // it's always wrong/insecure to try to create signatures with PublicKeys:
throw new IllegalArgumentException(PUB_KEY_SIGN_MSG);
}
// Implementation note: Ordinarily Passwords should not be used to create secure digests because they usually
// lack the length or entropy necessary for secure cryptographic operations, and are prone to misuse.
// However, we DO NOT prevent them as arguments here (like the above PublicKey check) because
// it is conceivable that a custom SecureDigestAlgorithm implementation would allow Password instances
// so that it might perform its own internal key-derivation logic producing a key that is then used to create a
// secure hash.
//
// Even so, a fallback safety check is that JJWT's only out-of-the-box Password implementation
// (io.jsonwebtoken.impl.security.PasswordSpec) explicitly forbids calls to password.getEncoded() in all
// scenarios to avoid potential misuse, so a digest algorithm implementation would explicitly need to avoid
// this by calling toCharArray() instead.
//
// TLDR; the digest algorithm implementation has the final say whether a password instance is valid
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
String id = Assert.hasText(alg.getId(), "SignatureAlgorithm id cannot be null or empty.");
if (Jwts.SIG.NONE.getId().equalsIgnoreCase(id)) {View on GitHub (pinned to fb71496164)
Solutions
- Pass the corresponding PrivateKey to signWith for token creation.
- Verify key usage before signing: if (key instanceof PublicKey) fail fast in your own code and use the private counterpart.
- Fix keystore/dependency injection so the signing component receives the private key and only verifiers receive the public key.
- Catch IllegalArgumentException and surface a clear configuration error.
Example fix
// before String jwt = Jwts.builder().signWith(publicKey, Jwts.SIG.RS256)...compact(); // after String jwt = Jwts.builder().signWith(privateKey, Jwts.SIG.RS256)...compact();
Defensive patterns
Strategy: validation
Validate before calling
if (key instanceof PublicKey) throw new IllegalArgumentException("signWith requires a PrivateKey"); Type guard
boolean canSign(Key k) { return !(k instanceof PublicKey) && k != null; } Try / catch
try { builder.signWith(key, alg); } catch (IllegalArgumentException e) { /* wrong key role — fail config check */ } Prevention
- Separate signing (PrivateKey) and verification (PublicKey) components
- Type helper methods as PrivateKey for signing APIs
- Add startup checks that the configured signing key is a PrivateKey
When it happens
Trigger: JwtBuilder.signWith(publicKey) or signWith(publicKey, alg) — any variant where the supplied key is an instance of java.security.PublicKey.
Common situations: Config mix-ups where the verification key is wired into the token-creation code path; loading the wrong key from a keystore; swapped key parameters in helper methods.
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
- Unable to determine a suitable MAC or Signature algorithm fo
- The 'none' JWS algorithm cannot be used to sign JWTs.
- PrivateKeys may not be used to encrypt data. PublicKeys are
- Unexpected unsecured Claims JWT.
- Unexpected content JWS.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/14243bea5836d12c.
Report an issue: GitHub.