apache/pulsar · error · JwtException

Found null Audience in token, for claimed field: ${audienceC

Error message

Found null Audience in token, for claimed field: ${audienceClaim}

What it means

authenticateToken() enforces audience validation when audienceClaim is configured: the JWT body must contain that claim. This check throws io.jsonwebtoken.JwtException (which authenticateToken wraps/rethrows) when the claim key exists in the config but the token's payload has a null/absent value for it — the token was issued without the audience claim the broker requires.

Source

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

    }

    private static String validateToken(final String token) throws AuthenticationException {
        if (StringUtils.isNotBlank(token)) {
            return token;
        } else {
            throw new AuthenticationException("Blank token found");
        }
    }

    @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.

View on GitHub (pinned to 820761864e)

Solutions

  1. Re-issue the token including the audience claim with the broker's audience value
  2. Align the token issuer's claim name with the broker's tokenAudienceClaim setting
  3. If audience validation is not needed, remove tokenAudienceClaim from broker config

Example fix

// before: token without aud claim
String token = Jwts.builder().setSubject("admin").signWith(key).compact();
// after
String token = Jwts.builder().setSubject("admin")
    .claim("aud", "pulsar") // or setAudience("pulsar")
    .signWith(key).compact();
Defensive patterns

Strategy: validation

Validate before calling

Claims claims = Jwts.parser().setSigningKey(key).build()
    .parseClaimsJws(token).getBody();
if (claims.get("aud") == null) {
    throw new JwtException("Token missing required audience claim");
}

Type guard

boolean hasAudienceClaim(Jws<Claims> jwt, String claim) {
    return jwt != null && jwt.getBody().get(claim) != null;
}

Try / catch

try {
    role = provider.authenticate(authData);
} catch (Exception e) {
    log.warn("Token rejected: missing audience claim; re-issue token with aud", e);
    return 401;
}

Prevention

When it happens

Trigger: A token parsed by parser.parseClaimsJws(token) whose Claims map returns null for the configured audienceClaim key, while the broker has tokenAudienceClaim set.

Common situations: Tokens issued by an older token issuer or a different tool that doesn't add the 'aud' (or custom) claim; changing the audienceClaim config name (e.g. from 'aud' to a custom name) without re-issuing tokens; mixing tokens from multiple issuers with different claim layouts.

Related errors


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