quarkusio/quarkus · error · io.quarkus.security.AuthenticationFailedException

Authentication has happened before the '@AuthenticationConte

Error message

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.

What it means

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.

Source

Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java:164

            @Override
            public Consumer<RoutingContext> apply(String annotationBinding) {
                int separatorIndex = annotationBinding.indexOf(ACR_VALUES_TO_MAX_AGE_SEPARATOR);
                String acrValues = annotationBinding.substring(0, separatorIndex);
                String maxAgeAsStr = annotationBinding.substring(separatorIndex + ACR_VALUES_TO_MAX_AGE_SEPARATOR.length());
                final Duration maxAgeDuration;
                if (maxAgeAsStr.isEmpty()) {
                    maxAgeDuration = null;
                } else {
                    maxAgeDuration = parseDuration(maxAgeAsStr);
                }
                StepUpAuthenticationPolicy policy = new StepUpAuthenticationPolicy(acrValues, maxAgeDuration);
                return new Consumer<RoutingContext>() {
                    @Override
                    public void accept(RoutingContext routingContext) {
                        String requestPath = routingContext.request().path();
                        OidcTenantConfig tenantConfig = routingContext.get(OidcTenantConfig.class.getName());
                        if (tenantConfig != null || routingContext.user() != null) {
                            throw new AuthenticationFailedException("""
                                    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.
                                    """.formatted(requestPath));
                        }
                        LOG.debugf("The '@AuthenticationContext' annotation set required 'acr' values '%s' "
                                + "and max age '%s' for the request path '%s'", acrValues, maxAgeAsStr, requestPath);
                        policy.storeSelfOnContext(routingContext);
                    }
                };
            }
        };
    }

    public Handler<RoutingContext> getBackChannelLogoutHandler(BeanContainer beanContainer) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Set 'quarkus.http.auth.permission."permissions".applies-to=JAXRS' on all HTTP Security Policies that secure the same REST endpoints annotated with @AuthenticationContext
  2. Remove or narrow HTTP Security Policies covering the annotated endpoints so they do not force early authentication
  3. Use @AuthenticationContext on endpoints not secured by proactive HTTP-level policies

Example fix

// before
quarkus.http.auth.permission.secured.paths=/rest/*
quarkus.http.auth.permission.secured.policy=authenticated
// after
quarkus.http.auth.permission.secured.paths=/rest/*
quarkus.http.auth.permission.secured.policy=authenticated
quarkus.http.auth.permission.secured.applies-to=JAXRS
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no proactive policy covers @AuthenticationContext paths
boolean proactive = policyPaths.stream().anyMatch(path -> endpointPath.startsWith(path) && !"JAXRS".equals(policyAppliesTo));
if (proactive) throw new IllegalStateException("Policy must use applies-to=JAXRS for " + endpointPath);

Try / catch

try { callApi(); } catch (AuthenticationFailedException e) { log.error("Auth ran before @AuthenticationContext matched; add applies-to=JAXRS to policies", e); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/2b00fc3df38a4ac0. Report an issue: GitHub.