{"record":{"id":"67a1c6f64f57559c","repo":"apache/pulsar","slug":"unauthorized-to-validateclusteroperation-for-origi","errorCode":null,"errorMessage":"Unauthorized to validateClusterOperation for originalPrincipal [${principal}] and clientAppId [${clientAppId}] about operation [${operation}] on cluster [${cluster}]","messagePattern":"Unauthorized to validateClusterOperation for originalPrincipal \\[(.+?)\\] and clientAppId \\[(.+?)\\] about operation \\[(.+?)\\] on cluster \\[(.+?)\\]","errorType":"http","errorClass":"RestException","httpStatus":401,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java","lineNumber":1306,"sourceCode":"                            .log(\"validateBothSuperuserAndClusterPolicyOperation failed\");\n                    throw new RestException(Status.UNAUTHORIZED,\n                            String.format(\"Unauthorized to validateBothSuperuserAndClusterPolicyOperation for\"\n                                          + \" originalPrincipal [%s] and clientAppId [%s] \"\n                                          + \"about operation [%s] on cluster [%s]\",\n                                    originalPrincipal(), clientAppId(), operation.toString(), clusterName));\n                });\n    }\n\n    private CompletableFuture<Void> validateClusterOperationAsync(String cluster, ClusterOperation operation) {\n        final var pulsar = pulsar();\n        if (pulsar.getBrokerService().isAuthenticationEnabled()\n            && pulsar.getBrokerService().isAuthorizationEnabled()) {\n            return pulsar.getBrokerService().getAuthorizationService()\n                    .allowClusterOperationAsync(cluster, operation, originalPrincipal(),\n                            clientAppId(), clientAuthData())\n                    .thenAccept(isAuthorized -> {\n                        if (!isAuthorized) {\n                            throw new RestException(Status.UNAUTHORIZED,\n                                    String.format(\"Unauthorized to validateClusterOperation for\"\n                                                  + \" originalPrincipal [%s] and clientAppId [%s] \"\n                                                  + \"about operation [%s] on cluster [%s]\",\n                                            originalPrincipal(), clientAppId(), operation.toString(), cluster));\n                        }\n                    });\n        }\n        return CompletableFuture.completedFuture(null);\n    }\n\n    private CompletableFuture<Void> validateClusterPolicyOperationAsync(String cluster, PolicyName policyName,\n                                                                        PolicyOperation operation) {\n        final var pulsar = pulsar();\n        if (pulsar.getBrokerService().isAuthenticationEnabled()\n            && pulsar.getBrokerService().isAuthorizationEnabled()) {\n            return pulsar.getBrokerService().getAuthorizationService()\n                    .allowClusterPolicyOperationAsync(cluster, policyName, operation, originalPrincipal(),\n                            clientAppId(), clientAuthData())","sourceCodeStart":1288,"sourceCodeEnd":1324,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java#L1288-L1324","documentation":"This 401 UNAUTHORIZED error is thrown by the broker's cluster-level authorization check. When authorization is enabled on the broker, every admin cluster operation is delegated to the AuthorizationService's allowClusterOperationAsync; if it returns false, the REST layer rejects the request with this message naming the original principal, client app id, operation, and cluster. It means the authenticated role lacks the required cluster policy permission.","triggerScenarios":"Calling any admin cluster REST endpoint (e.g. GET/PUT /admin/v3/clusters/{cluster}) with authorizationEnabled=true while the role has no cluster grant; the role was authenticated successfully but not authorized for the specific cluster operation.","commonSituations":"Missing or stale authorization provider configuration; admin client using a token/role that was never granted cluster access; wildcard or role grants misconfigured in the authorization provider; after rotating credentials the new role lacks grants.","solutions":["Grant the principal permission for the cluster operation, e.g. via the broker authorization provider's config or a grant: pulsar-admin or the AuthorizationService grant for role + cluster + operation.","If the user should be an admin, configure the role in superUserRoles in broker.conf.","Verify brokerService.isAuthorizationEnabled matches your intended security posture (temporarily false for debugging only).","Inspect the originalPrincipal/clientAppId in the message and confirm it is the role you intended to authenticate as (token may map to an unexpected subject)."],"exampleFix":"// before: admin role with no cluster grant gets 401\n// after: grant cluster operation to the role in the authorization provider\n// e.g. in AuthzProvider (or via existing grant APIs)\nauthorizationService.grantPermissionAsync(clusterName,\n    Set.of(ClusterOperation.GET), role, null);\n// or broker.conf\nsuperUserRoles=my-admin-role","handlingStrategy":"validation","validationCode":"// before the call, check the role has the grant (using the admin API)\nSet<String> perms = admin.clusters().getClusterPermission(cluster); // or your provider's lookup\nif (!perms.contains(role)) { /* grant or use a superuser role first */ }","typeGuard":null,"tryCatchPattern":"try { admin.clusters().getCluster(cluster); }\ncatch (PulsarAdminException e) {\n  if (e.getStatusCode() == 401) {\n    log.error(\"Not authorized for cluster op as {}\", e.getMessage());\n  } else throw e;\n}","preventionTips":["Keep a grant matrix of role -> cluster operations in your authorization provider config","Use superUserRoles for infrastructure admin automation","After credential rotation, re-verify grants for the new role","Log the originalPrincipal/clientAppId from the error to confirm identity mapping"],"tags":["authorization","rest-api","admin","clusters"],"backgroundTag":"broker-authorization-denied","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}