apache/pulsar · error · IllegalArgumentException
The ${alg.name()} algorithm does not support Key Pairs.
Error message
The ${alg.name()} algorithm does not support Key Pairs. What it means
keyTypeForSignatureAlgorithm only maps RSA-family and ECDSA-family algorithms to a JCE KeyFactory type; any other SignatureAlgorithm reaches the else branch and throws IllegalArgumentException. It exists to support asymmetric (key-pair based) algorithms only.
Source
Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/utils/AuthTokenUtils.java:86
public static PublicKey decodePublicKey(byte[] key, SignatureAlgorithm algType) throws IOException {
try {
X509EncodedKeySpec spec = new X509EncodedKeySpec(key);
KeyFactory kf = KeyFactory.getInstance(keyTypeForSignatureAlgorithm(algType));
return kf.generatePublic(spec);
} catch (Exception e) {
throw new IOException("Failed to decode public key", e);
}
}
private static String keyTypeForSignatureAlgorithm(SignatureAlgorithm alg) {
if (alg.getFamilyName().equals("RSA")) {
return "RSA";
} else if (alg.getFamilyName().equals("ECDSA")) {
return "EC";
} else {
String msg = "The " + alg.name() + " algorithm does not support Key Pairs.";
throw new IllegalArgumentException(msg);
}
}
public static String encodeKeyBase64(Key key) {
return Encoders.BASE64.encode(key.getEncoded());
}
public static String createToken(Key signingKey, String subject, Optional<Date> expiryTime,
Optional<Map<String, Object>> headers) {
JwtBuilder builder = Jwts.builder()
.setSubject(subject)
.signWith(signingKey);
expiryTime.ifPresent(builder::setExpiration);
headers.ifPresent(builder::setHeaderParams);
return builder.compact();
}View on GitHub (pinned to 820761864e)
Solutions
- Switch the SignatureAlgorithm to an asymmetric one (RS256/RS512 or ES256/ES512) when using public/private key pairs.
- If you intend symmetric signing, use the secret-key API (a shared base64 secret) instead of key-pair/public-key APIs.
- Check broker.conf `tokenSigningAlgorithm`/client algorithm configuration for a leftover HSxxx value.
Example fix
// before SignatureAlgorithm alg = SignatureAlgorithm.HS256; // symmetric, no key pair PublicKey pk = AuthTokenUtils.decodePublicKey(keyBytes, alg); // after SignatureAlgorithm alg = SignatureAlgorithm.RS256; // asymmetric PublicKey pk = AuthTokenUtils.decodePublicKey(keyBytes, alg);
Defensive patterns
Strategy: validation
Validate before calling
String fam = alg.getFamilyName();
if (!fam.equals("RSA") && !fam.equals("ECDSA")) throw new IllegalArgumentException("use RSA/ECDSA alg for key pairs, got " + alg); Type guard
boolean isAsymmetric(SignatureAlgorithm alg) { return alg.getFamilyName().equals("RSA") || alg.getFamilyName().equals("ECDSA"); } Try / catch
try { ...keyPairApi(alg); } catch (IllegalArgumentException e) { log.error("{}: use HSxxx with a shared secret instead", e.getMessage()); } Prevention
- Use HSxxx only with secret-based token APIs
- Audit broker.conf algorithm settings when migrating from symmetric to asymmetric tokens
- Prefer RS256/ES256 defaults for key-pair setups
When it happens
Trigger: Calling decodePublicKey or the key-pair generation path with an HMAC-family SignatureAlgorithm such as HS256, HS384, or HS512, since symmetric algorithms have no public/private key pair.
Common situations: Broker configured with `tokenSecretKey`-style settings while the algorithm is left at the JWT default HS256; copying configuration from a symmetric-token setup and switching the algorithm name without generating RSA/EC keys.
Related errors
- Failed to decode public key
- Illegal base64 character or Key file ${keyConfUrl} doesn't e
- Secret/Public Key file ${keyConfUrl} doesn't exist
- SHA-256 algorithm not found
- certFilePath must not be null
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/b779ff75da39f4e2.
Report an issue: GitHub.