{"record":{"id":"29a45d59e281c1cb","repo":"apache/pulsar","slug":"don-t-have-permission-to-access-this-topic","errorCode":null,"errorMessage":"Don't have permission to access this topic","messagePattern":"Don't have permission to access this topic","errorType":"http","errorClass":"RestException","httpStatus":401,"severity":"error","filePath":"pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/WebSocketWebResource.java","lineNumber":142,"sourceCode":"     * @param topic\n     * @throws RestException\n     */\n    protected void validateUserAccess(TopicName topic) {\n        boolean isAuthorized = false;\n\n        try {\n            validateSuperUserAccess();\n            isAuthorized = true;\n        } catch (Exception e) {\n            try {\n                isAuthorized = isAuthorized(topic);\n            } catch (Exception ne) {\n                throw new RestException(ne);\n            }\n        }\n\n        if (!isAuthorized) {\n            throw new RestException(Status.UNAUTHORIZED, \"Don't have permission to access this topic\");\n        }\n    }\n\n    /**\n     * Checks if user is authorized to produce/consume on a given topic.\n     *\n     * @param topic\n     * @return\n     * @throws Exception\n     */\n    protected boolean isAuthorized(TopicName topic) throws Exception {\n        if (service().isAuthorizationEnabled()) {\n            return service().getAuthorizationService().canLookup(topic, clientAppId(), authData());\n        }\n        return true;\n    }\n}\n","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/admin/WebSocketWebResource.java#L124-L160","documentation":"The WebSocket proxy validates that the authenticated role is authorized to produce, consume, or read the requested topic before proxying the connection. If all authorization checks (AuthorizationProvider, admin API lookup) complete without granting access, the endpoint throws this HTTP 401 RestException and rejects the WebSocket handshake.","triggerScenarios":"A client connects to /ws/producer, /ws/consumer, or /ws/reader for a topic while its authenticated role lacks produce/consume/lookup permissions, or the AuthorizationProvider returns false / throws and no check sets isAuthorized=true.","commonSituations":"Missing namespace/topic-level grant for the role; wrong auth token or misconfigured authMethod so the proxy authorizes the wrong role; broker adminApiUrl or auth plugin misconfiguration in websocket.conf causing lookup failure; topic removed after URL was built.","solutions":["Grant the role access to the topic: pulsar-admin namespaces grant-permissions or topics set-permissions with the role used by the client's credentials","Fix the client's authentication (correct token/key, matching auth plugin and parameters in websocket.conf) so the intended role is authenticated","Verify websocket.conf brokerWebServiceUrl and auth provider settings so the proxy can perform authorization lookups","Check broker logs for exceptions in validateUserAccess that make the authorization check itself fail rather than return false"],"exampleFix":"// client shell: wrong/no token -> 401\nws://broker:8080/ws/reader/my-topic\n// after adding auth:\nws://broker:8080/ws/reader/my-topic\nAuthorization: Bearer <token-for-role-with-access>  (or token query param)\n// and/or grant access:\npulsar-admin topics grant-permissions persistent://public/default/my-topic --role app1 --actions produce,consume","handlingStrategy":"try-catch","validationCode":"// before opening the WS connection\nboolean ok = admin.namespaces().getPermissions(\"public/default\")\n    .entrySet().stream()\n    .anyMatch(e -> e.getKey().equals(myRole) &&\n        e.getValue().contains(AuthAction.produce) ||\n        e.getValue().contains(AuthAction.consume));\nif (!ok) throw new IllegalStateException(\"role lacks access to topic\");","typeGuard":null,"tryCatchPattern":"try (Client wsClient = ... ) {\n  wsClient.newConsumer().topic(topic).subscribe();\n} catch (PulsarClientException e) {\n  if (e.getStatusCode() == 401 || String.valueOf(e).contains(\"Don't have permission\")) {\n    log.error(\"Not authorized for topic {} — check role grants and auth config\", topic);\n    // do not retry; permissions must be fixed\n  } else throw e;\n}","preventionTips":["Grant the exact authenticated role produce/consume actions on the topic/namespace","Keep websocket.conf auth plugin/parameters in sync with broker auth config","After rotating credentials, re-verify WS lookup works before deploying","Watch for topic-lookup failures in proxy logs that mask real auth errors"],"tags":["authorization","websocket","http-401","pulsar"],"backgroundTag":"unauthorized-topic-access","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"}