{"record":{"id":"87c655cbff222488","repo":"quarkusio/quarkus","slug":"the-1-s-selected-with-the-tenant-annotation-mu","errorCode":null,"errorMessage":"The '%1$s' selected with the @Tenant annotation must be used to authenticate the request but it was already authenticated with the '%2$s' tenant. It can happen if the '%1$s' is selected with an annotation but '%2$s' is resolved during authentication required by the HTTP Security Policy which is enforced 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 where the '%1$s' tenant is resolved by the '@Tenant' annotation.","messagePattern":"The '%1\\$s' selected with the @Tenant annotation must be used to authenticate the request but it was already authenticated with the '%2\\$s' tenant\\. It can happen if the '%1\\$s' is selected with an annotation but '%2\\$s' is resolved during authentication required by the HTTP Security Policy which is enforced 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 where the '%1\\$s' tenant is resolved by the '@Tenant' 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":109,"sourceCode":"    }\n\n    public Function<String, Consumer<RoutingContext>> tenantResolverInterceptorCreator() {\n        return new Function<String, Consumer<RoutingContext>>() {\n            @Override\n            public Consumer<RoutingContext> apply(String tenantId) {\n                return new Consumer<RoutingContext>() {\n                    @Override\n                    public void accept(RoutingContext routingContext) {\n                        OidcTenantConfig tenantConfig = routingContext.get(OidcTenantConfig.class.getName());\n                        if (tenantConfig != null) {\n                            // authentication has happened before @Tenant annotation was matched with the HTTP request\n                            String tenantUsedForAuth = tenantConfig.tenantId().orElse(null);\n                            if (tenantId.equals(tenantUsedForAuth)) {\n                                // @Tenant selects the same tenant as already selected\n                                return;\n                            } else {\n                                // @Tenant selects the different tenant than already selected\n                                throw new AuthenticationFailedException(\n                                        \"\"\"\n                                                The '%1$s' selected with the @Tenant annotation must be used to authenticate\n                                                the request but it was already authenticated with the '%2$s' tenant. It\n                                                can happen if the '%1$s' is selected with an annotation but '%2$s' is\n                                                resolved during authentication required by the HTTP Security Policy which\n                                                is enforced before the JAX-RS chain is run. In such cases, please set the\n                                                'quarkus.http.auth.permission.\"permissions\".applies-to=JAXRS' to all HTTP\n                                                Security Policies which secure the same REST endpoints as the ones\n                                                where the '%1$s' tenant is resolved by the '@Tenant' annotation.\n                                                \"\"\"\n                                                .formatted(tenantId, tenantUsedForAuth));\n                            }\n                        }\n\n                        LOG.debugf(\"@Tenant annotation set a '%s' tenant id on the %s request path\", tenantId,\n                                routingContext.request().path());\n                        routingContext.put(OidcUtils.TENANT_ID_SET_BY_ANNOTATION, tenantId);\n                        routingContext.put(OidcUtils.TENANT_ID_ATTRIBUTE, tenantId);","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java#L91-L127","documentation":"Quarkus OIDC throws this when a JAX-RS endpoint selects a tenant via the @Tenant annotation, but the request was already authenticated with a different tenant. This happens because HTTP Security Policies run authentication before the JAX-RS chain, resolving a different tenant. The framework detects the mismatch between the pre-authenticated tenant and the annotation-selected tenant and rejects the request.","triggerScenarios":"A request matches an HTTP Security Policy that forces authentication (resolving tenant '%2$s' via the default or custom tenant resolver) before the JAX-RS chain runs; later the endpoint's @Tenant annotation resolves tenant '%1$s', which differs from the already-authenticated tenant, so OidcRecorder's RoutingContext consumer throws AuthenticationFailedException.","commonSituations":"Multi-tenant OIDC apps where quarkus.http.auth.permission policies secure REST endpoints without applies-to=JAXRS; mixing @Tenant-annotated endpoints with global HTTP auth policies; adding a new security policy that unintentionally triggers early authentication for tenant-scoped endpoints.","solutions":["Set 'quarkus.http.auth.permission.\"permissions\".applies-to=JAXRS' on every HTTP Security Policy that secures the same endpoints as the @Tenant annotation","Ensure the tenant resolved by the HTTP Security Policy matches the tenant selected with @Tenant, or remove the policy's early authentication for those paths","Review custom TenantResolver implementations so they resolve consistently at both the policy and JAX-RS phases"],"exampleFix":"// before\nquarkus.http.auth.permission.authenticated.paths=/api/*\nquarkus.http.auth.permission.authenticated.policy=authenticated\n// after\nquarkus.http.auth.permission.authenticated.paths=/api/*\nquarkus.http.auth.permission.authenticated.policy=authenticated\nquarkus.http.auth.permission.authenticated.applies-to=JAXRS","handlingStrategy":"validation","validationCode":"// Verify policies covering @Tenant endpoints use applies-to=JAXRS\nList.of(\"quarkus.http.auth.permission.\" + name + \".applies-to\")\n    .forEach(p -> check(config.getProperty(p).equals(\"JAXRS\"), p + \" must be JAXRS\"));","typeGuard":null,"tryCatchPattern":"try { callApi(); } catch (AuthenticationFailedException e) { log.error(\"Tenant mismatch: set applies-to=JAXRS on matching HTTP policies\", e); throw new WebApplicationException(401); }","preventionTips":["Always set applies-to=JAXRS on policies securing @Tenant-annotated endpoints","Audit HTTP Security Policy paths against @Tenant endpoint paths each release","Write an integration test asserting @Tenant endpoints authenticate with the annotated tenant"],"tags":["oidc","multi-tenant","http-security-policy","jaxrs"],"backgroundTag":"tenant-authentication-mismatch","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}