quarkusio/quarkus · error · IllegalStateException

An exception should have been thrown because authentication

Error message

An exception should have been thrown because authentication happened before Tenant was selected with the @Tenant annotation

What it means

This IllegalStateException is thrown by the TenantEchoResource endpoint /http-security-policy-applies-all-diff as a canary: when a @Tenant annotation is combined with an HTTP SecurityPolicy that applies to all paths, authentication must never happen before the tenant is selected. Reaching this method body proves the ordering guarantee was violated, so the endpoint always fails loudly.

Source

Thrown at integration-tests/oidc-wiremock/src/main/java/io/quarkus/it/keycloak/TenantEchoResource.java:60

    @Path("/hr-classic-and-jaxrs-perm-check")
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getHrTenantClassicAndJaxRsPermCheck() {
        return getTenantInternal();
    }

    @PermissionsAllowed("get-tenant")
    @Path("/hr-identity-augmentation")
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getHrTenantIdentityAugmentation() {
        return getTenantInternal();
    }

    @Path("/http-security-policy-applies-all-diff")
    @GET
    public String httpSecurityPolicyAppliesAllDiff() {
        throw new IllegalStateException("An exception should have been thrown because authentication happened" +
                " before Tenant was selected with the @Tenant annotation");
    }

    @Path("/http-security-policy-applies-all-same")
    @GET
    public String httpSecurityPolicyAppliesAllSame() {
        return getTenantInternal();
    }

    private String getTenantInternal() {
        return OidcUtils.TENANT_ID_ATTRIBUTE + "=" + routingContext.get(OidcUtils.TENANT_ID_ATTRIBUTE)
                + ", static.tenant.id=" + routingContext.get("static.tenant.id")
                + ", name=" + identity.getPrincipal().getName()
                + ", " + OidcUtils.TENANT_ID_SET_BY_ANNOTATION + "="
                + routingContext.get(OidcUtils.TENANT_ID_SET_BY_ANNOTATION);
    }
}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Verify the HTTP SecurityPolicy is registered so it does not force authentication before tenant selection for @Tenant-annotated endpoints.
  2. Check that the @Tenant interceptor runs prior to authentication in this configuration.
  3. Review recent changes to HTTP SecurityPolicy appliesTo=ALL handling in the Quarkus version under test.
  4. Enable DEBUG logging for io.quarkus.vertx.http.runtime.security and io.quarkus.oidc to inspect ordering.

Example fix

// before (broken ordering — endpoint reached after authentication)
@Path("/http-security-policy-applies-all-diff")
@GET
public String httpSecurityPolicyAppliesAllDiff() {
    throw new IllegalStateException("authentication happened before @Tenant was selected");
}
// after (correct ordering: tenant selected before auth; method returns normally)
@Path("/http-security-policy-applies-all-diff")
@GET
@Tenant("diff")
public String httpSecurityPolicyAppliesAllDiff() {
    return getTenantInternal();
}
Defensive patterns

Strategy: type-guard

Validate before calling

// in a test, assert the endpoint is never reachable with an authenticated identity
RestAssured.get("/http-security-policy-applies-all-diff")
    .then().statusCode(500); // must not return 200

Type guard

boolean tenantSelectedBeforeAuth(SecurityIdentity identity, Tenant currentTenant) {
    return currentTenant != null && identity != null && identity.isAnonymous() == false
            && TENANT_AUTH_ORDER.isTenantFirst(); // custom ordering check
}

Try / catch

try {
    tenantEchoResource.httpSecurityPolicyAppliesAllDiff();
} catch (IllegalStateException e) {
    assertTrue(e.getMessage().contains("before Tenant was selected"));
}

Prevention

When it happens

Trigger: GET /http-security-policy-applies-all-diff is dispatched and Quarkus HTTP security policy authentication runs before the @Tenant annotation-based tenant selection resolves the tenant — i.e. a regression in security-policy vs tenant-interceptor ordering.

Common situations: Upgrading Quarkus versions where HTTP SecurityPolicy execution order changed, adding a policy with appliesTo=all while using @Tenant on the same endpoint, or misconfigured policy registration in the application.

Understand the failure class

Related errors


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