apache/pulsar · error · AuthenticationException

ALGORITHM_MISMATCH

ALGORITHM_MISMATCH

Error message

Expected PublicKey alg [

What it means

While building the java-jwt Algorithm in verifyJWT, casting the provided PublicKey to the type implied by publicKeyAlg (e.g., (RSAPublicKey) or (ECPublicKey)) failed with ClassCastException — the key's actual type does not match the configured algorithm name. The provider throws AuthenticationException(ALGORITHM_MISMATCH) with a message that (despite the wording) means the expected and actual key types disagree.

Source

Thrown at pulsar-broker-auth-oidc/src/main/java/org/apache/pulsar/broker/authentication/oidc/AuthenticationProviderOpenID.java:439

                case ALG_RS512:
                    alg = Algorithm.RSA512((RSAPublicKey) publicKey, null);
                    break;
                case ALG_ES256:
                    alg = Algorithm.ECDSA256((ECPublicKey) publicKey, null);
                    break;
                case ALG_ES384:
                    alg = Algorithm.ECDSA384((ECPublicKey) publicKey, null);
                    break;
                case ALG_ES512:
                    alg = Algorithm.ECDSA512((ECPublicKey) publicKey, null);
                    break;
                default:
                    incrementFailureMetric(AuthenticationExceptionCode.UNSUPPORTED_ALGORITHM);
                    throw new AuthenticationException("Unsupported algorithm: " + publicKeyAlg);
            }
        } catch (ClassCastException e) {
            incrementFailureMetric(AuthenticationExceptionCode.ALGORITHM_MISMATCH);
            throw new AuthenticationException("Expected PublicKey alg [" + publicKeyAlg + "] does match actual alg.");
        }

        // We verify issuer when retrieving the PublicKey, so it is not verified here.
        // The claim presence requirements are based on https://openid.net/specs/openid-connect-basic-1_0.html#IDToken
         Verification verifierBuilder = JWT.require(alg)
                .acceptLeeway(acceptedTimeLeewaySeconds)
                .withAnyOfAudience(allowedAudiences)
                .withClaimPresence(RegisteredClaims.ISSUED_AT)
                .withClaimPresence(RegisteredClaims.EXPIRES_AT)
                .withClaimPresence(RegisteredClaims.SUBJECT);

        if (isRoleClaimNotSubject) {
            verifierBuilder = verifierBuilder.withClaimPresence(roleClaim);
        }

        JWTVerifier verifier = verifierBuilder.build();

        try {

View on GitHub (pinned to 820761864e)

Solutions

  1. Clear the broker's cached JWKS/keys (restart or let the cache refresh) so key 'kid' and algorithm mappings re-resolve together
  2. Verify that the key file/keystore you configured matches the configured algorithm (RS256/384/512 require an RSA public key; ES256/384/512 require an EC P-256/P-384/P-521 key)
  3. Check that your OIDC provider hasn't rotated signing keys to a different family; update the broker configuration accordingly
  4. When loading keys manually, validate key.getAlgorithm() equals the configured publicKeyAlg before calling verifyJWT

Example fix

// before: EC key configured under an RSA algorithm name
publicKeyAlg = "RS256"; publicKey = loadEcPem("idp_ec.pem");
// after: pair matches
publicKeyAlg = "ES256"; publicKey = loadEcPem("idp_ec.pem");
Defensive patterns

Strategy: validation

Validate before calling

boolean algMatchesKey(String alg, PublicKey k) {
    boolean isRsa = alg.startsWith("RS");
    boolean isEc  = alg.startsWith("ES");
    return (isRsa && k instanceof RSAPublicKey) || (isEc && k instanceof ECPublicKey);
}

Try / catch

try {
    return verifyJWT(publicKey, publicKeyAlg, jwt);
} catch (AuthenticationException e) {
    if (e.getMessage().startsWith("Expected PublicKey alg")) {
        log.error("Key/algorithm mismatch: expected {} got {}", publicKeyAlg, publicKey.getAlgorithm());
    }
    throw e;
}

Prevention

When it happens

Trigger: verifyJWT() receives a publicKey whose runtime type contradicts publicKeyAlg: an EC key while publicKeyAlg says RS256 (or vice versa), an X509/invalid key object, or a null key typed in a way that fails the cast in one of the switch's cast branches.

Common situations: Broker keystore/cache holds a key fetched under the wrong 'kid' so an RSA alg is paired with an EC key; IdP rotated keys and rotated to a different family (RSA -> EC) but the broker cached the old algorithm mapping; manual key configuration specifying RS256 while loading an EC .pem.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/82b825a00ac0b736. Report an issue: GitHub.