{"record":{"id":"bdb50ada17291b53","repo":"apache/pulsar","slug":"audiences-in-token-audiences-not-contains-th","errorCode":null,"errorMessage":"Audiences in token: [${audiences}] not contains this broker: ${audience}","messagePattern":"Audiences in token: \\[(.+?)\\] not contains this broker: (.+?)","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java","lineNumber":248,"sourceCode":"    }\n\n    @SuppressWarnings(\"unchecked\")\n    private Jws<Claims> authenticateToken(final String token) throws AuthenticationException {\n        try {\n            Jws<Claims> jwt = parser.parseClaimsJws(token);\n\n            if (audienceClaim != null) {\n                Object object = jwt.getBody().get(audienceClaim);\n                if (object == null) {\n                    throw new JwtException(\"Found null Audience in token, for claimed field: \" + audienceClaim);\n                }\n\n                if (object instanceof Collection) {\n                    Collection<String> audiences = (Collection<String>) object;\n                    // audience not contains this broker, throw exception.\n                    if (audiences.stream().noneMatch(audienceInToken -> audienceInToken.equals(audience))) {\n                        incrementFailureMetric(ErrorCode.INVALID_AUDIENCES);\n                        throw new AuthenticationException(\"Audiences in token: [\"\n                                + String.join(\", \", audiences) + \"] not contains this broker: \" + audience);\n                    }\n                } else if (object instanceof String) {\n                    if (!object.equals(audience)) {\n                        incrementFailureMetric(ErrorCode.INVALID_AUDIENCES);\n                        throw new AuthenticationException(\n                                \"Audiences in token: [\" + object + \"] not contains this broker: \" + audience);\n                    }\n                } else {\n                    // should not reach here.\n                    incrementFailureMetric(ErrorCode.INVALID_AUDIENCES);\n                    throw new AuthenticationException(\"Audiences in token is not in expected format: \" + object);\n                }\n            }\n\n            var expiration = jwt.getBody().getExpiration();\n            var tokenRemainingDurationMs = expiration != null ? expiration.getTime() - new Date().getTime() : null;\n            authenticationMetricsToken.recordTokenDuration(tokenRemainingDurationMs);","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderToken.java#L230-L266","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nString token = Jwts.builder().claim(\"aud\", List.of(\"other-service\")).signWith(key).compact();\n// after\nString token = Jwts.builder().claim(\"aud\", List.of(\"other-service\", \"pulsar\")).signWith(key).compact();","handlingStrategy":"validation","validationCode":"Object aud = claims.get(\"aud\");\nboolean ok = (aud instanceof String && \"pulsar\".equals(aud))\n        || (aud instanceof Collection && ((Collection<?>) aud).contains(\"pulsar\"));\nif (!ok) {\n    throw new AuthenticationException(\"Token audience does not include this broker\");\n}","typeGuard":"boolean audiencesInclude(Object aud, String expected) {\n    if (aud instanceof String s) return s.equals(expected);\n    if (aud instanceof Collection<?> c) return c.contains(expected);\n    return false;\n}","tryCatchPattern":"try {\n    role = provider.authenticate(authData);\n} catch (AuthenticationException e) {\n    log.warn(\"Token audience mismatch: {}\", e.getMessage());\n    return 403;\n}","preventionTips":["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"],"tags":["jwt","token","audience"],"backgroundTag":"jwt-audience-mismatch","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}