apache/pulsar · error · RestException

Need to authenticate to perform the request

Error message

Need to authenticate to perform the request

What it means

If both authentication and authorization are enabled, validateAdminAccessForTenantAsync requires an authenticated client identity. When clientAppId is null/blank (unauthenticated request), it throws RestException with HTTP 403 'Need to authenticate to perform the request' — you must authenticate before tenant-admin authorization can be evaluated.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java:343

    protected CompletableFuture<Void> validateAdminAccessForTenantAsync(
            PulsarService pulsar, String clientAppId,
            String originalPrincipal, String tenant,
            AuthenticationDataSource authenticationData) {
            log.debug()
                    .attr("tenant", tenant)
                    .attr("authenticated", (isClientAuthenticated(clientAppId)))
                    .attr("role", clientAppId)
                    .log("check admin access on tenant");
                return pulsar.getPulsarResources().getTenantResources().getTenantAsync(tenant)
                .thenCompose(tenantInfoOptional -> {
                    if (tenantInfoOptional.isEmpty()) {
                        throw new RestException(Status.NOT_FOUND, "Tenant does not exist");
                    }
                    TenantInfo tenantInfo = tenantInfoOptional.get();
                    if (pulsar.getConfiguration().isAuthenticationEnabled() && pulsar.getConfiguration()
                            .isAuthorizationEnabled()) {
                        if (!isClientAuthenticated(clientAppId)) {
                            throw new RestException(Status.FORBIDDEN, "Need to authenticate to perform the request");
                        }
                        validateOriginalPrincipal(clientAppId, originalPrincipal);
                        if (pulsar.getConfiguration().getProxyRoles().contains(clientAppId)) {
                            AuthorizationService authorizationService =
                                    pulsar.getBrokerService().getAuthorizationService();
                            return authorizationService.isTenantAdmin(tenant, clientAppId, tenantInfo,
                                            authenticationData)
                                .thenCompose(isTenantAdmin -> {
                                    if (!isTenantAdmin) {
                                            return authorizationService.isSuperUser(clientAppId, authenticationData)
                                                .thenCombine(authorizationService.isSuperUser(originalPrincipal,
                                                             authenticationData),
                                                     (proxyAuthorized, originalPrincipalAuthorized) -> {
                                                         if (!proxyAuthorized || !originalPrincipalAuthorized) {
                                                             throw new RestException(Status.UNAUTHORIZED,
                                                                     String.format("Proxy not authorized to access "
                                                                                     + "resource (proxy:%s,original:%s)"
                                                                             , clientAppId, originalPrincipal));

View on GitHub (pinned to 820761864e)

Solutions

  1. Send valid credentials (e.g. Authorization: Bearer <token>) with the request
  2. Fix the client's auth plugin configuration (provider, token/credentials file, issuer URL)
  3. Check broker logs/authentication plugin to see why no role was derived from the presented credentials
  4. If the endpoint is intentionally open, adjust broker authenticationEnabled — not recommended for admin APIs

Example fix

// before
curl http://broker:8080/admin/v2/tenants/mytenant
// after
curl -H "Authorization: Bearer $ADMIN_TOKEN" http://broker:8080/admin/v2/tenants/mytenant
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side pre-check: PulsarAdmin built without Authentication will send no credentials
if (pulsarAdmin.getClientConfig() == null || !hasAuthPlugin(pulsarAdmin)) {
    throw new IllegalStateException("PulsarAdmin must be configured with an Authentication provider");
}

Try / catch

try {
    admin.tenants().getTenant(tenant);
} catch (PulsarAdminException e) {
    if (e.getStatusCode() == 403) {
        // refresh credentials / reconfigure the auth plugin
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling a tenant-admin endpoint without credentials while broker has authenticationEnabled=true and authorizationEnabled=true; client sends no/malformed Authorization header so the auth plugin yields no role; anonymous access to a tenant-scoped endpoint.

Common situations: curl/scripts missing the auth token; expired token rejected in a way that leaves no principal; misconfigured client auth plugin (wrong provider/parameters); broker auth enabled after clients were built without auth support.

Understand the failure class

Related errors


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