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

  1. Check the wrapped cause message for the provider's exact rejection reason (invalid modulus, exponent, spec).
  2. Verify the private key loads correctly and its CRT parameters are consistent (e.g. compare getModulus against a freshly loaded copy).
  3. 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

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


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)