jwtk/jjwt · error · IllegalArgumentException

PublicKeys may not be used to decrypt data. PublicKeys are u

Error message

PublicKeys may not be used to decrypt data. PublicKeys are used to encrypt, and PrivateKeys are used to decrypt.

What it means

Thrown as IllegalArgumentException from DefaultJwtParserBuilder.decryptWith(Key) when a PublicKey is supplied for JWE decryption. Public keys encrypt; only the corresponding PrivateKey may decrypt, so passing a PublicKey indicates inverted key usage in the JWE flow.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java:297

            throw new IllegalArgumentException(DefaultJwtParser.PRIV_KEY_VERIFY_MSG);
        }
        this.signatureVerificationKey = Assert.notNull(key, "signature verification key cannot be null.");
        return this;
    }

    @Override
    public JwtParserBuilder decryptWith(SecretKey key) {
        return decryptWith((Key) key);
    }

    @Override
    public JwtParserBuilder decryptWith(PrivateKey key) {
        return decryptWith((Key) key);
    }

    private JwtParserBuilder decryptWith(final Key key) {
        if (key instanceof PublicKey) {
            throw new IllegalArgumentException(DefaultJwtParser.PUB_KEY_DECRYPT_MSG);
        }
        this.decryptionKey = Assert.notNull(key, "decryption key cannot be null.");
        return this;
    }

    @Override
    public NestedCollection<CompressionAlgorithm, JwtParserBuilder> zip() {
        return new NestedIdentifiableCollection<CompressionAlgorithm, JwtParserBuilder>(this, this.zipAlgs) {
            @Override
            protected void changed() {
                zipAlgs = new IdRegistry<>(StandardCompressionAlgorithms.NAME, getValues().values());
            }
        };
    }

    @Override
    public NestedCollection<AeadAlgorithm, JwtParserBuilder> enc() {
        return new NestedIdentifiableCollection<AeadAlgorithm, JwtParserBuilder>(this, this.encAlgs) {

View on GitHub (pinned to fb71496164)

Solutions

  1. Pass the corresponding PrivateKey to decryptWith(...) on the receiving side.
  2. Keep the public key only on the sender's side (encryptWith / builder).
  3. Confirm the JWE algorithm family (RSA-OAEP, ECDH-ES, dir, etc.) and that your key type matches it.
  4. If both parties need the same key, use a symmetric SecretKey (AES) with a 'dir' or key-wrap algorithm instead.

Example fix

// before
PublicKey pub = loadRecipientPublicKey();
Jwts.parser().decryptWith(pub).build().parseEncryptedClaims(jwe); // IllegalArgumentException
// after
PrivateKey priv = loadRecipientPrivateKey();
Jwts.parser().decryptWith(priv).build().parseEncryptedClaims(jwe);
Defensive patterns

Strategy: type-guard

Validate before calling

if (key instanceof java.security.PublicKey) {
    throw new IllegalArgumentException("Refusing to configure a PublicKey for decryption");
}

Type guard

boolean isDecryptionKey(java.security.Key k) {
    return k instanceof java.security.PrivateKey || k instanceof javax.crypto.SecretKey;
}

Try / catch

try {
    builder.decryptWith(key);
} catch (IllegalArgumentException e) {
    // PublicKey supplied: use the matching PrivateKey (or SecretKey for 'dir')
}

Prevention

When it happens

Trigger: Calling parserBuilder.decryptWith(publicKey) to parse an encrypted JWT (JWE); typically when the developer confuses the encryption side (public key) with the decryption side (private key).

Common situations: Client encrypts with the recipient's public key but the recipient misconfigures decryptWith with that same public key; symmetric/asymmetric algorithm confusion after switching from MAC to RSA-OAEP; reading documentation examples out of order.

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/90e823104c1e7cd7. Report an issue: GitHub.