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
- Issue a new token whose aud claim includes the broker's configured audience value
- Set the broker's tokenAudience to match the audience baked into the existing tokens
- 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
- Issue tokens per-cluster with the correct audience value
- Keep tokenAudience stable or plan token re-issuance on change
- Verify which token/authParams each environment's clients actually use
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
- Token Audience Claim [${audienceClaim}] configured, but Audi
- No token credentials passed
- Blank token found
- Found null Audience in token, for claimed field: ${audienceC
- Audiences in token: [${object}] not contains this broker: ${
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/bdb50ada17291b53.
Report an issue: GitHub.