{"record":{"id":"2b00fc3df38a4ac0","repo":"quarkusio/quarkus","slug":"authentication-has-happened-before-the-authentic","errorCode":null,"errorMessage":"Authentication has happened before the '@AuthenticationContext' annotation was matched with the HTTP request path '%s'. It can happen when the authentication is required by an HTTP Security Policy before the JAX-RS chain is run. In such cases, please set the 'quarkus.http.auth.permission.\"permissions\".applies-to=JAXRS' to all HTTP Security Policies which secure the same REST endpoints as the ones annotated with the '@AuthenticationContext' annotation.","messagePattern":"Authentication has happened before the '@AuthenticationContext' annotation was matched with the HTTP request path '(.+?)'\\. It can happen when the authentication is required by an HTTP Security Policy before the JAX-RS chain is run\\. In such cases, please set the 'quarkus\\.http\\.auth\\.permission\\.\"permissions\"\\.applies-to=JAXRS' to all HTTP Security Policies which secure the same REST endpoints as the ones annotated with the '@AuthenticationContext' annotation\\.","errorType":"exception","errorClass":"io.quarkus.security.AuthenticationFailedException","httpStatus":401,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java","lineNumber":164,"sourceCode":"            @Override\n            public Consumer<RoutingContext> apply(String annotationBinding) {\n                int separatorIndex = annotationBinding.indexOf(ACR_VALUES_TO_MAX_AGE_SEPARATOR);\n                String acrValues = annotationBinding.substring(0, separatorIndex);\n                String maxAgeAsStr = annotationBinding.substring(separatorIndex + ACR_VALUES_TO_MAX_AGE_SEPARATOR.length());\n                final Duration maxAgeDuration;\n                if (maxAgeAsStr.isEmpty()) {\n                    maxAgeDuration = null;\n                } else {\n                    maxAgeDuration = parseDuration(maxAgeAsStr);\n                }\n                StepUpAuthenticationPolicy policy = new StepUpAuthenticationPolicy(acrValues, maxAgeDuration);\n                return new Consumer<RoutingContext>() {\n                    @Override\n                    public void accept(RoutingContext routingContext) {\n                        String requestPath = routingContext.request().path();\n                        OidcTenantConfig tenantConfig = routingContext.get(OidcTenantConfig.class.getName());\n                        if (tenantConfig != null || routingContext.user() != null) {\n                            throw new AuthenticationFailedException(\"\"\"\n                                    Authentication has happened before the '@AuthenticationContext' annotation was\n                                    matched with the HTTP request path '%s'. It can happen when the authentication\n                                    is required by an HTTP Security Policy before the JAX-RS chain is run. In such\n                                    cases, please set the 'quarkus.http.auth.permission.\"permissions\".applies-to=JAXRS'\n                                    to all HTTP Security Policies which secure the same REST endpoints as the ones\n                                    annotated with the '@AuthenticationContext' annotation.\n                                    \"\"\".formatted(requestPath));\n                        }\n                        LOG.debugf(\"The '@AuthenticationContext' annotation set required 'acr' values '%s' \"\n                                + \"and max age '%s' for the request path '%s'\", acrValues, maxAgeAsStr, requestPath);\n                        policy.storeSelfOnContext(routingContext);\n                    }\n                };\n            }\n        };\n    }\n\n    public Handler<RoutingContext> getBackChannelLogoutHandler(BeanContainer beanContainer) {","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java#L146-L182","documentation":"Quarkus OIDC throws this when the @AuthenticationContext annotation is matched to the request path, but authentication already happened for the request. Authentication required by an HTTP Security Policy runs before the JAX-RS chain, so the annotation never gets a chance to control authentication. The framework detects an existing tenant config or authenticated user at annotation-matching time and fails the request.","triggerScenarios":"A request to a path annotated with @AuthenticationContext matches an HTTP Security Policy requiring authentication; the policy resolves the tenant and authenticates before the JAX-RS chain, so when the annotation's consumer runs (OidcRecorder.accept) it finds tenantConfig != null or routingContext.user() != null and throws AuthenticationFailedException.","commonSituations":"Endpoints annotated with @AuthenticationContext that are also covered by quarkus.http.auth.permission policies without applies-to=JAXRS; apps migrating to annotation-based authentication while keeping global security policies; wildcard policies accidentally covering annotated endpoints.","solutions":["Set 'quarkus.http.auth.permission.\"permissions\".applies-to=JAXRS' on all HTTP Security Policies that secure the same REST endpoints annotated with @AuthenticationContext","Remove or narrow HTTP Security Policies covering the annotated endpoints so they do not force early authentication","Use @AuthenticationContext on endpoints not secured by proactive HTTP-level policies"],"exampleFix":"// before\nquarkus.http.auth.permission.secured.paths=/rest/*\nquarkus.http.auth.permission.secured.policy=authenticated\n// after\nquarkus.http.auth.permission.secured.paths=/rest/*\nquarkus.http.auth.permission.secured.policy=authenticated\nquarkus.http.auth.permission.secured.applies-to=JAXRS","handlingStrategy":"validation","validationCode":"// Ensure no proactive policy covers @AuthenticationContext paths\nboolean proactive = policyPaths.stream().anyMatch(path -> endpointPath.startsWith(path) && !\"JAXRS\".equals(policyAppliesTo));\nif (proactive) throw new IllegalStateException(\"Policy must use applies-to=JAXRS for \" + endpointPath);","typeGuard":null,"tryCatchPattern":"try { callApi(); } catch (AuthenticationFailedException e) { log.error(\"Auth ran before @AuthenticationContext matched; add applies-to=JAXRS to policies\", e); }","preventionTips":["Pair every @AuthenticationContext endpoint with JAXRS-scoped policies only","Avoid wildcard HTTP Security Policy paths that swallow annotated endpoints","Test annotated endpoints for 401/403 behavior after adding new policies"],"tags":["oidc","authentication-context","http-security-policy","jaxrs"],"backgroundTag":"early-authentication-conflict","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}