{"record":{"id":"6072ddedc881c699","repo":"apache/pulsar","slug":"failed-to-decode-public-key","errorCode":null,"errorMessage":"Failed to decode public key","messagePattern":"Failed to decode public key","errorType":"validation","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/utils/AuthTokenUtils.java","lineNumber":75,"sourceCode":"\n    public static PrivateKey decodePrivateKey(byte[] key, SignatureAlgorithm algType) throws IOException {\n        try {\n            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key);\n            KeyFactory kf = KeyFactory.getInstance(keyTypeForSignatureAlgorithm(algType));\n            return kf.generatePrivate(spec);\n        } catch (Exception e) {\n            throw new IOException(\"Failed to decode private key\", e);\n        }\n    }\n\n\n    public static PublicKey decodePublicKey(byte[] key, SignatureAlgorithm algType) throws IOException {\n        try {\n            X509EncodedKeySpec spec = new X509EncodedKeySpec(key);\n            KeyFactory kf = KeyFactory.getInstance(keyTypeForSignatureAlgorithm(algType));\n            return kf.generatePublic(spec);\n        } catch (Exception e) {\n            throw new IOException(\"Failed to decode public key\", e);\n        }\n    }\n\n    private static String keyTypeForSignatureAlgorithm(SignatureAlgorithm alg) {\n        if (alg.getFamilyName().equals(\"RSA\")) {\n            return \"RSA\";\n        } else if (alg.getFamilyName().equals(\"ECDSA\")) {\n            return \"EC\";\n        } else {\n            String msg = \"The \" + alg.name() + \" algorithm does not support Key Pairs.\";\n            throw new IllegalArgumentException(msg);\n        }\n    }\n\n    public static String encodeKeyBase64(Key key) {\n        return Encoders.BASE64.encode(key.getEncoded());\n    }\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/utils/AuthTokenUtils.java#L57-L93","documentation":"AuthTokenUtils.decodePublicKey wraps any failure while parsing an X.509-encoded public key (for RSA or EC signature algorithms) into an IOException. KeyFactory.generatePublic rejects the bytes if they are not a valid DER/X.509 SubjectPublicKeyInfo structure or do not match the expected key algorithm.","triggerScenarios":"Calling decodePublicKey(byte[], SignatureAlgorithm) with bytes that are not a valid X509EncodedKeySpec: corrupted key file contents, a PEM body with surrounding junk, a private key passed where a public key is expected, or truncated base64 input.","commonSituations":"Passing the contents of a PKCS#8 private key file instead of the public key; pasting a raw hex key instead of base64 DER; hand-editing a key file and corrupting the encoding; using a key generated for a different algorithm than the configured algType.","solutions":["Verify the input is a public key in X.509/SubjectPublicKeyInfo (SPKI) DER format; regenerate with `openssl rsa -pubout` or `openssl ec -pubout` and base64-encode the DER bytes.","Strip PEM armor and whitespace before calling decodePublicKey — it expects raw DER bytes, not the '-----BEGIN PUBLIC KEY-----' text.","Ensure the SignatureAlgorithm matches the key family (RSA key with RSA alg, EC key with ECDSA alg).","Confirm the base64 string decodes cleanly (Decoders.BASE64.decode in a test) and was not truncated by copy/paste or line wrapping."],"exampleFix":"// before\nbyte[] key = Files.readAllBytes(Path.of(\"public.key\")); // file contains PEM text\nPublicKey pk = AuthTokenUtils.decodePublicKey(key, SignatureAlgorithm.RS256);\n// after\nString pem = Files.readString(Path.of(\"public.key\"));\nString b64 = pem.replaceAll(\"-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\\\\s\", \"\");\nbyte[] key = Base64.getDecoder().decode(b64);\nPublicKey pk = AuthTokenUtils.decodePublicKey(key, SignatureAlgorithm.RS256);","handlingStrategy":"validation","validationCode":"byte[] der = Base64.getDecoder().decode(cleanB64);\nif (der.length == 0 || der[0] != 0x30) throw new IllegalArgumentException(\"not DER/SPKI public key\");\nnew X509EncodedKeySpec(der); // parses or throws before calling the API","typeGuard":"boolean isSpkiPublicKey(byte[] b) { return b != null && b.length > 0 && b[0] == 0x30; }","tryCatchPattern":"try { PublicKey pk = AuthTokenUtils.decodePublicKey(bytes, alg); } catch (IOException e) { log.error(\"bad public key material\", e); throw new ConfigurationException(\"check tokenPublicKey: must be base64 X.509 SPKI\"); }","preventionTips":["Always generate public keys with `openssl -pubout` and base64-encode the DER form","Strip PEM headers/footers and whitespace before decoding","Never pass private-key bytes to decodePublicKey","Match the key family to the SignatureAlgorithm"],"tags":["authentication","crypto","key-parsing","java"],"backgroundTag":"invalid-public-key-format","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}