apache/pulsar · error · AuthenticationException

Audiences in token: [${object}] not contains this broker: ${

Error message

Audiences in token: [${object}] not contains this broker: ${audience}

What it means

AuthenticationProviderToken throws this AuthenticationException in authenticateToken when the JWT's audience claim (tokenAudienceClaim, if configured) does not contain the audience value this broker expects (tokenAudience). The broker verifies that the token was issued specifically for it; a token whose aud claim lists other audiences is rejected even though its signature is valid.

Source

Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java:254

            if (audienceClaim != null) {
                Object object = jwt.getBody().get(audienceClaim);
                if (object == null) {
                    throw new JwtException("Found null Audience in token, for claimed field: " + audienceClaim);
                }

                if (object instanceof Collection) {
                    Collection<String> audiences = (Collection<String>) object;
                    // audience not contains this broker, throw exception.
                    if (audiences.stream().noneMatch(audienceInToken -> audienceInToken.equals(audience))) {
                        incrementFailureMetric(ErrorCode.INVALID_AUDIENCES);
                        throw new AuthenticationException("Audiences in token: ["
                                + String.join(", ", audiences) + "] not contains this broker: " + audience);
                    }
                } else if (object instanceof String) {
                    if (!object.equals(audience)) {
                        incrementFailureMetric(ErrorCode.INVALID_AUDIENCES);
                        throw new AuthenticationException(
                                "Audiences in token: [" + object + "] not contains this broker: " + audience);
                    }
                } else {
                    // should not reach here.
                    incrementFailureMetric(ErrorCode.INVALID_AUDIENCES);
                    throw new AuthenticationException("Audiences in token is not in expected format: " + object);
                }
            }

            var expiration = jwt.getBody().getExpiration();
            var tokenRemainingDurationMs = expiration != null ? expiration.getTime() - new Date().getTime() : null;
            authenticationMetricsToken.recordTokenDuration(tokenRemainingDurationMs);
            return jwt;
        } catch (JwtException e) {
            if (e instanceof ExpiredJwtException) {
                authenticationMetricsToken.recordTokenExpired();
            }
            incrementFailureMetric(ErrorCode.INVALID_TOKEN);

View on GitHub (pinned to 820761864e)

Solutions

  1. Re-issue the token including this broker's tokenAudience value in the aud claim (e.g. with pulsar tokens create --audience <brokerAudience>).
  2. Check the broker's tokenAudience setting in broker.conf/standalone.conf and make it match the audience used by your token issuer.
  3. If audience validation is not needed, remove the tokenAudienceClaim/tokenAudience configuration so the check is skipped.
  4. Decode the token (e.g. jwt.io) to inspect the actual aud claim and compare it to the broker's audience string for typos or trailing whitespace.

Example fix

// before: token issued without matching audience
pulsar tokens create --secret-key $SECRET --subject my-role
// after
pulsar tokens create --secret-key $SECRET --subject my-role --audience "urn:my-broker"
Defensive patterns

Strategy: validation

Validate before calling

// Decode token payload (no libs needed with jjwt on classpath):
String[] parts = token.split("\\.");
String payload = new java.util.Base64.getUrlDecoder().decode(parts[1]);
org.json.JSONObject claims = new org.json.JSONObject(payload);
Object aud = claims.opt("aud"); // or your configured audienceClaim
boolean ok = (aud instanceof String && audience.equals(aud))
    || (aud instanceof org.json.JSONArray && ((org.json.JSONArray) aud).toList().contains(audience));
if (!ok) { throw new IllegalStateException("token audience does not include broker audience " + audience); }

Type guard

static boolean hasValidAudience(Object claimValue, String expected) {
    if (claimValue instanceof String) return expected.equals(claimValue);
    if (claimValue instanceof Collection<?>) return ((Collection<?>) claimValue).contains(expected);
    return false;
}

Try / catch

try {
    String role = authProvider.authenticate(authData);
} catch (AuthenticationException e) {
    if (e.getMessage().contains("not contains this broker")) {
        log.warn("Token audience mismatch; re-issue token with audience {}", brokerAudience);
    }
}

Prevention

When it happens

Trigger: A client authenticates with a token whose aud claim is a single string not equal to the broker's configured tokenAudience, or whose audience collection contains no entry equal to it, while authenticationProviderAudienceClaim/tokenAudience is configured on the broker.

Common situations: A token minted for another service (e.g. a different broker cluster or component) is reused against this broker; the broker's tokenAudience was changed or set after the token was issued; the issuer used a singular aud claim that doesn't match the broker's expected audience string.

Related errors


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