{"record":{"id":"69f8738e2965a2af","repo":"quarkusio/quarkus","slug":"websocket-endpoint-s-has-method-s-secured-wi","errorCode":null,"errorMessage":"WebSocket endpoint '%s' has method '%s' secured with the '%s' security annotation.\nOnly the HTTP upgrade can be secured with this annotation.\nPlease place the annotation on the endpoint class instead.\n","messagePattern":"WebSocket endpoint '(.+?)' has method '(.+?)' secured with the '(.+?)' security annotation\\.\nOnly the HTTP upgrade can be secured with this annotation\\.\nPlease place the annotation on the endpoint class instead\\.\n","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java","lineNumber":1006,"sourceCode":"                        var superName = beanClassInfo.superName();\n                        while (superName != null && !OBJECT.equals(superName)) {\n                            var superClass = index.getClassByName(superName);\n                            if (superClass != null\n                                    && securityTransformer.hasSecurityAnnotation(superClass, AUTHORIZATION_POLICY)) {\n                                throw new IllegalStateException(\"\"\"\n                                        WebSocket endpoint '%s' superclass '%s' is secured with the '%s' security annotation.\n                                        Only the HTTP upgrade can be secured with this annotation.\n                                        Please place the annotation on the endpoint class '%s' instead.\n                                        \"\"\".formatted(endpoint.id, superClass.name(), AuthorizationPolicy.class.getName(),\n                                        beanName));\n                            } else {\n                                superName = superClass == null ? null : superClass.superName();\n                            }\n                        }\n                    }\n                    beanClassInfo.methods().forEach(mi -> {\n                        if (securityTransformer.hasSecurityAnnotation(mi, AUTHORIZATION_POLICY)) {\n                            throw new IllegalStateException(\"\"\"\n                                    WebSocket endpoint '%s' has method '%s' secured with the '%s' security annotation.\n                                    Only the HTTP upgrade can be secured with this annotation.\n                                    Please place the annotation on the endpoint class instead.\n                                    \"\"\".formatted(beanName, mi.name(), AuthorizationPolicy.class.getName()));\n                        }\n                    });\n                })\n                .collect(groupingBy(PolicyToEndpoint::policyName, mapping(PolicyToEndpoint::endpointId, toSet())));\n    }\n\n    static String mergePath(String prefix, String path) {\n        if (prefix.endsWith(\"/\")) {\n            prefix = prefix.substring(0, prefix.length() - 1);\n        }\n        if (!path.startsWith(\"/\")) {\n            path = \"/\" + path;\n        }\n        return prefix + path;","sourceCodeStart":988,"sourceCodeEnd":1024,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java#L988-L1024","documentation":"AuthorizationPolicy secures only the HTTP upgrade, so it must be placed on the endpoint class — never on individual endpoint methods. The processor scans all methods of each endpoint class during build and fails if any carries the annotation.","triggerScenarios":"A method of a @WebSocket endpoint class (e.g. an @OnMessage/@OnOpen callback) is annotated with @AuthorizationPolicy; the build-time check securityTransformer.hasSecurityAnnotation(mi, AUTHORIZATION_POLICY) matches and throws.","commonSituations":"Trying to secure individual message handlers as one would secure JAX-RS resource methods; auto-import/auto-complete adding the annotation at method level; applying copy-pasted security annotations from REST endpoints to WebSocket callbacks.","solutions":["Remove @AuthorizationPolicy from the method and place it on the endpoint class instead.","Secure per-connection authorization inside the callback using SecurityIdentity / WebSocketSecurity APIs if per-operation checks are truly needed.","Review all endpoint methods for stray security annotations copied from REST resources.","Use the endpoint-class-level policy or HTTP upgrade security policy for coarse-grained control."],"exampleFix":"// before\n@WebSocket(path = \"/ws\")\npublic class MyEndpoint {\n    @OnMessage\n    @AuthorizationPolicy(name = \"admin\")\n    void onMessage(String msg) { }\n}\n\n// after\n@WebSocket(path = \"/ws\")\n@AuthorizationPolicy(name = \"admin\")\npublic class MyEndpoint {\n    @OnMessage\n    void onMessage(String msg) { }\n}","handlingStrategy":"validation","validationCode":"// Pre-check: no endpoint method may carry @AuthorizationPolicy\nfor (Method m : MyEndpoint.class.getDeclaredMethods()) {\n    if (m.isAnnotationPresent(io.quarkus.security.AuthorizationPolicy.class))\n        throw new IllegalStateException(\"@AuthorizationPolicy belongs on the endpoint class, not \" + m);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember @AuthorizationPolicy secures only the HTTP upgrade — class level only","Do not copy method-level security annotations from JAX-RS resources","Use class-level policy or in-callback SecurityIdentity checks for fine-grained control","Add an ArchUnit/test rule rejecting @AuthorizationPolicy on methods of @WebSocket classes"],"tags":["quarkus","websockets-next","security","authorization","build-time"],"backgroundTag":"security-annotation-wrong-placement","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}