{"record":{"id":"14243bea5836d12c","repo":"jwtk/jjwt","slug":"publickeys-may-not-be-used-to-create-digital-signa","errorCode":null,"errorMessage":"PublicKeys may not be used to create digital signatures. PrivateKeys are used to sign, and PublicKeys are used to verify.","messagePattern":"PublicKeys may not be used to create digital signatures\\. PrivateKeys are used to sign, and PublicKeys are used to verify\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java","lineNumber":217,"sourceCode":"            throw new UnsupportedKeyException(msg);\n        }\n        return alg;\n    }\n\n    @Override\n    public JwtBuilder signWith(Key key) throws InvalidKeyException {\n        Assert.notNull(key, \"Key argument cannot be null.\");\n        SecureDigestAlgorithm<Key, ?> alg = forSigningKey(key); // https://github.com/jwtk/jjwt/issues/381\n        return signWith(key, alg);\n    }\n\n    @Override\n    public <K extends Key> JwtBuilder signWith(K key, final SecureDigestAlgorithm<? super K, ?> alg)\n            throws InvalidKeyException {\n\n        Assert.notNull(key, \"Key argument cannot be null.\");\n        if (key instanceof PublicKey) { // it's always wrong/insecure to try to create signatures with PublicKeys:\n            throw new IllegalArgumentException(PUB_KEY_SIGN_MSG);\n        }\n        // Implementation note:  Ordinarily Passwords should not be used to create secure digests because they usually\n        // lack the length or entropy necessary for secure cryptographic operations, and are prone to misuse.\n        // However, we DO NOT prevent them as arguments here (like the above PublicKey check) because\n        // it is conceivable that a custom SecureDigestAlgorithm implementation would allow Password instances\n        // so that it might perform its own internal key-derivation logic producing a key that is then used to create a\n        // secure hash.\n        //\n        // Even so, a fallback safety check is that JJWT's only out-of-the-box Password implementation\n        // (io.jsonwebtoken.impl.security.PasswordSpec) explicitly forbids calls to password.getEncoded() in all\n        // scenarios to avoid potential misuse, so a digest algorithm implementation would explicitly need to avoid\n        // this by calling toCharArray() instead.\n        //\n        // TLDR; the digest algorithm implementation has the final say whether a password instance is valid\n\n        Assert.notNull(alg, \"SignatureAlgorithm cannot be null.\");\n        String id = Assert.hasText(alg.getId(), \"SignatureAlgorithm id cannot be null or empty.\");\n        if (Jwts.SIG.NONE.getId().equalsIgnoreCase(id)) {","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java#L199-L235","documentation":"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.","triggerScenarios":"JwtBuilder.signWith(publicKey) or signWith(publicKey, alg) — any variant where the supplied key is an instance of java.security.PublicKey.","commonSituations":"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.","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."],"exampleFix":"// before\nString jwt = Jwts.builder().signWith(publicKey, Jwts.SIG.RS256)...compact();\n// after\nString jwt = Jwts.builder().signWith(privateKey, Jwts.SIG.RS256)...compact();","handlingStrategy":"validation","validationCode":"if (key instanceof PublicKey) throw new IllegalArgumentException(\"signWith requires a PrivateKey\");","typeGuard":"boolean canSign(Key k) { return !(k instanceof PublicKey) && k != null; }","tryCatchPattern":"try { builder.signWith(key, alg); } catch (IllegalArgumentException e) { /* wrong key role — fail config check */ }","preventionTips":["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"],"tags":["jwt","signing","key-misuse"],"backgroundTag":"invalid-argument-value","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}