apache/pulsar · error · AuthenticationException

NO_PUBLIC_KEY

NO_PUBLIC_KEY

Error message

Unable to retrieve ZTS Public Key

What it means

authenticate() asks the Athenz AuthZpeClient for the ZTS public key matching the token's keyId. If it returns null, errorCode NO_PUBLIC_KEY is set and this AuthenticationException is thrown: the broker cannot obtain the signing key needed to verify the token's signature, so verification cannot proceed.

Source

Thrown at pulsar-broker-auth-athenz/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderAthenz.java:155

                        .attr("clientAddress", clientAddress)
                        .log("Athenz RoleToken received from Client");

            RoleToken token = new RoleToken(roleToken);

            if (!domainNameList.contains(token.getDomain())) {
                errorCode = ErrorCode.DOMAIN_MISMATCH;
                throw new AuthenticationException(
                        String.format("Athenz RoleToken Domain mismatch, Expected: %s, Found: %s",
                                domainNameList.toString(), token.getDomain()));
            }

            // Synchronize for non-thread safe static calls inside athenz library
            synchronized (this) {
                PublicKey ztsPublicKey = AuthZpeClient.getZtsPublicKey(token.getKeyId());

                if (ztsPublicKey == null) {
                    errorCode = ErrorCode.NO_PUBLIC_KEY;
                    throw new AuthenticationException("Unable to retrieve ZTS Public Key");
                }

                if (token.validate(ztsPublicKey, allowedOffset, false, null)) {
                    log.debug().attr("roleToken", roleToken)
                            .attr("clientAddress", clientAddress)
                            .log("Athenz Role Token Authenticated for Client");
                    authenticationMetrics.recordSuccess();
                    return token.getPrincipal();
                } else {
                    errorCode = ErrorCode.INVALID_TOKEN;
                    throw new AuthenticationException(
                            String.format("Athenz Role Token Not Authenticated from Client: %s", clientAddress));
                }
            }
        } catch (AuthenticationException exception) {
            incrementFailureMetric(errorCode);
            throw exception;
        }

View on GitHub (pinned to 820761864e)

Solutions

  1. Refresh the ZTS public key material on the broker (update athenz zts public key files/config) so the token's keyId resolves.
  2. Restart or re-initialize the provider to force AuthZpeClient to reload keys after ZTS rotation.
  3. Confirm the token comes from the same ZTS environment as the broker's configured keys (check keyId against your ZTS).
  4. Update the athenz client library so its key-refresh/caching behavior matches your ZTS rotation interval.

Example fix

// before
# broker host has stale key
/etc/athenz/zts_public_key.pem   (old K_id, missing rotated key)
// after
# re-fetch from ZTS and install current keys
wget https://zts.example.com:8443/zts/v1/publicKey -O /etc/athenz/zts_public_key.pem
systemctl restart pulsar-broker
Defensive patterns

Strategy: retry

Validate before calling

// after provider init, sanity check key availability for expected keyIds
PublicKey k = AuthZpeClient.getZtsPublicKey(expectedKeyId);
if (k == null) { /* refresh zts public key files before serving traffic */ }

Try / catch

try {
    principal = provider.authenticate(authData);
} catch (AuthenticationException e) {
    if (e.getMessage().contains("Unable to retrieve ZTS Public Key")) {
        // refresh key material / reload provider, then retry once
    }
    throw e;
}

Prevention

When it happens

Trigger: AuthZpeClient.getZtsPublicKey(token.getKeyId()) returns null because the keyId is unknown — the ZTS rotated keys and the broker's public key cache is stale, or the token was issued by a ZTS the broker has no key material for.

Common situations: Athenz ZTS key rotation without refreshing the broker's key files / zts public key config; clock-triggered cache expiry in AuthZpeClient; tokens issued by a different ZTS environment (dev vs prod); corrupted or outdated athenz.conf public key files on the broker host.

Related errors


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