apache/pulsar · error · RestException
Proxy not authorized to access resource (proxy:%s,original:%
Error message
Proxy not authorized to access resource (proxy:%s,original:%s)
What it means
When a request arrives through a broker configured as a proxy role, Pulsar checks admin access for both the proxy identity (clientAppId) and the forwarded original principal. If neither the proxy nor the original principal is a super user (and the proxy is not a tenant admin), validateAdminAccessForTenantAsync throws 401 UNAUTHORIZED with this message. This is a deliberate anti-spoofing check on the proxy header chain.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java:358
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));
} else {
log.debug()
.attr("principal", originalPrincipal)
.attr("proxy", clientAppId)
.attr("tenant", tenant)
.log("Authorized on tenant");
return null;
}
});
} else {
log.debug().attr("principal", originalPrincipal)
.attr("proxy", clientAppId)
.attr("tenant", tenant)
.log("Successfully authorized on tenant");
return CompletableFutureView on GitHub (pinned to 820761864e)
Solutions
- Add the proxy role (clientAppId) to the broker's superUserRoles, or grant it tenant admin via the authorization provider
- Ensure the proxy forwards the original principal header and that the original principal is a super user or tenant admin
- Bypass the proxy and call the target broker directly with valid superuser credentials to confirm the proxy config is the problem
- Check the configured AuthorizationProvider logic for isSuperUser/isTenantAdmin against your auth source
Example fix
// before (proxy.conf) superUserRoles=my-admin proxyRoles=Pulsar-Proxy // after superUserRoles=my-admin,Pulsar-Proxy
Defensive patterns
Strategy: validation
Validate before calling
// Verify proxy and original principal are superusers before issuing admin calls via proxy
Set<String> superUsers = getBrokerConfig().getSuperUserRoles();
String proxyRole = getClientRole();
String originalPrincipal = request.getHeader("X-Original-Principal");
if (!superUsers.contains(proxyRole) || originalPrincipal == null || !superUsers.contains(originalPrincipal)) {
throw new IllegalStateException("proxy/original principal not in superUserRoles: " + proxyRole + ", " + originalPrincipal);
} Type guard
boolean isAuthorizedProxy(String proxyRole, String originalPrincipal, Set<String> superUsers, Set<String> tenantAdmins) {
return superUsers.contains(proxyRole) || tenantAdmins.contains(proxyRole)
? superUsers.contains(originalPrincipal) || tenantAdmins.contains(originalPrincipal)
: false;
} Prevention
- Keep the proxy role in superUserRoles on the backing broker
- Always forward X-Original-Principal (and original auth data) through the proxy
- Test proxy-based admin calls after every authorizationProvider/config change
When it happens
Trigger: Calling any tenant-admin REST API through a proxy-role broker where: the proxy role is not a super user, and the original principal (from the X-Original-Principal header) is not a super user, and the proxy role is not a tenant admin of the target tenant. E.g. pulsar-admin with a proxy broker configured via brokerClientAuthenticationParameters pointing at a tenant the proxy was never granted admin on.
Common situations: Proxy/broker misconfiguration where getProxyRoles includes the frontend broker but superusers does not list the proxy role or the forwarded principal; missing X-Original-Principal forwarding so the original principal is null/unauthenticated; after tightening authorizationProvider config the proxy lost superuser status.
Related errors
- Don't have permission to administrate resources on this tena
- Unauthorized to validateBothSuperuserAndBrokerOperation for
- Unauthorized to validateBrokerOperation for originalPrincipa
- Invalid combination of Original principal cannot be empty if
- Proxy not authorized for super-user operation (proxy:%s)
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/37eceb5e9aacf919.
Report an issue: GitHub.