apache/pulsar · error · AuthenticationException

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

Error message

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

What it means

When the audience claim is present, authenticateToken() verifies it names this broker's configured audience. It throws this AuthenticationException when the claim is a collection and none of its entries equal the configured audience — the token is validly signed but was minted for a different broker/service, so it is rejected.

Source

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

    }

    @SuppressWarnings("unchecked")
    private Jws<Claims> authenticateToken(final String token) throws AuthenticationException {
        try {
            Jws<Claims> jwt = parser.parseClaimsJws(token);

            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);

View on GitHub (pinned to 820761864e)

Solutions

  1. Issue a new token whose aud claim includes the broker's configured audience value
  2. Set the broker's tokenAudience to match the audience baked into the existing tokens
  3. Verify the correct token file/authParams is deployed on the client (not a token from another environment)

Example fix

// before
String token = Jwts.builder().claim("aud", List.of("other-service")).signWith(key).compact();
// after
String token = Jwts.builder().claim("aud", List.of("other-service", "pulsar")).signWith(key).compact();
Defensive patterns

Strategy: validation

Validate before calling

Object aud = claims.get("aud");
boolean ok = (aud instanceof String && "pulsar".equals(aud))
        || (aud instanceof Collection && ((Collection<?>) aud).contains("pulsar"));
if (!ok) {
    throw new AuthenticationException("Token audience does not include this broker");
}

Type guard

boolean audiencesInclude(Object aud, String expected) {
    if (aud instanceof String s) return s.equals(expected);
    if (aud instanceof Collection<?> c) return c.contains(expected);
    return false;
}

Try / catch

try {
    role = provider.authenticate(authData);
} catch (AuthenticationException e) {
    log.warn("Token audience mismatch: {}", e.getMessage());
    return 403;
}

Prevention

When it happens

Trigger: Token's audienceClaim is a Collection whose values do not include the broker's configured tokenAudience; noneMatch(...) is true, so the exception fires with the list of audiences found in the token.

Common situations: Using a token issued for another Pulsar cluster or another service (e.g. a token minted for 'api://serviceA' used against broker audience 'pulsar'); broker's tokenAudience changed after tokens were issued; multi-tenant setups sharing tokens across brokers.

Related errors


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