jwtk/jjwt · error · InvalidKeyException
Unable to derive RSAPublicKey from RSAPrivateKey
Error message
Unable to derive RSAPublicKey from RSAPrivateKey ${ctx}. Cause: ${e.getMessage()} What it means
Thrown as InvalidKeyException when jjwt tries to derive the RSAPublicKey from an RSAPrivateKey's modulus and public exponent (via JCA KeyFactory.generatePublic with RSAPublicKeySpec) and the JCA provider rejects it. The message embeds the JwkContext and underlying cause.
Solutions
- Check the wrapped cause message for the provider's exact rejection reason (invalid modulus, exponent, spec).
- Verify the private key loads correctly and its CRT parameters are consistent (e.g. compare getModulus against a freshly loaded copy).
- Supply the real RSAPublicKey alongside the private key so derivation is not needed, or regenerate the keypair with Jwts.SIG.RSxxx.keyPair().
Example fix
// before Jwk<RSAPrivateKey> jwk = Jwts.CLK... // only private key provided, derivation fails // after KeyPair kp = Jwts.SIG.RS256.keyPair().build(); // or build JWK from a keypair that includes a valid public key
Defensive patterns
Strategy: try-catch
Validate before calling
RSAPublicKeySpec spec = new RSAPublicKeySpec(privKey.getModulus(), ((RSAPrivateCrtKey) privKey).getPublicExponent()); // test derivation yourself first
Type guard
boolean canDerivePublic(RSAPrivateKey k) { return k instanceof RSAPrivateCrtKey && k.getModulus() != null && ((RSAPrivateCrtKey) k).getPublicExponent() != null; } Try / catch
try { /* create JWK */ } catch (InvalidKeyException e) { log.error("Public key derivation failed: {}", e.getMessage()); throw e; } Prevention
- Verify modulus/publicExponent pair with KeyFactory before handing the key to jjwt.
- Prefer providing the real KeyPair rather than relying on derivation.
- Beware of keys mutated or partially deserialized by third-party code.
When it happens
Trigger: Creating a JWK from an RSAPrivateKey whose modulus or recovered public exponent is invalid/inconsistent, causing KeyFactory.generatePublic to fail inside the derivePublic path of RsaPrivateJwkFactory.
Common situations: Corrupted or truncated key encodings; keys with mismatched modulus/exponent pairs from custom deserialization; buggy or restrictive JCA providers.
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
- ${e.getMessage()}
- Invalid RSA key algorithm name.
- JWE Header epk value is not an Elliptic Curve Public JWK…
- RSA JWK 'oth' (Other Prime Info) element cannot be null.
- RSA JWK 'oth' (Other Prime Info) element map cannot be…
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/90e23622bd2854b8.
Report an issue: GitHub.
Appendix: source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/RsaPrivateJwkFactory.java:97
}
String msg = String.format(PUB_EXPONENT_EX_MSG, KeysBridge.toString(key));
throw new UnsupportedKeyException(msg);
}
private RSAPublicKey derivePublic(final JwkContext<RSAPrivateKey> ctx) {
RSAPrivateKey key = ctx.getKey();
BigInteger modulus = key.getModulus();
BigInteger publicExponent = getPublicExponent(key);
final RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent);
return generateKey(ctx, RSAPublicKey.class, new CheckedFunction<KeyFactory, RSAPublicKey>() {
@Override
public RSAPublicKey apply(KeyFactory kf) {
try {
return (RSAPublicKey) kf.generatePublic(spec);
} catch (Exception e) {
String msg = "Unable to derive RSAPublicKey from RSAPrivateKey " + ctx + ". Cause: " + e.getMessage();
throw new InvalidKeyException(msg);
}
}
});
}
@Override
protected RsaPrivateJwk createJwkFromKey(JwkContext<RSAPrivateKey> ctx) {
RSAPrivateKey key = ctx.getKey();
RSAPublicKey rsaPublicKey;
PublicKey publicKey = ctx.getPublicKey();
if (publicKey != null) {
rsaPublicKey = Assert.isInstanceOf(RSAPublicKey.class, publicKey, PUBKEY_ERR_MSG);
} else {
rsaPublicKey = derivePublic(ctx);
}
View on GitHub (pinned to fb71496164)