quarkusio/quarkus · error · RuntimeException

Invalid tenant id

Error message

Invalid tenant id

What it means

SessionExpiredOidcRedirectFilter filters OIDC redirects and validates that the redirect belongs to the 'tenant-refresh' tenant. When the OIDC tenant id in the redirect context is anything else, it throws to fail fast, since the filter was designed exclusively for the tenant-refresh session-expired flow.

Source

Thrown at integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/SessionExpiredOidcRedirectFilter.java:27

import io.quarkus.oidc.OidcRedirectFilter;
import io.quarkus.oidc.Redirect;
import io.quarkus.oidc.Redirect.Location;
import io.quarkus.oidc.TenantFeature;
import io.quarkus.oidc.common.runtime.OidcCommonUtils;
import io.quarkus.oidc.runtime.OidcUtils;
import io.smallrye.jwt.build.Jwt;

@ApplicationScoped
@Unremovable
@TenantFeature("tenant-refresh")
@Redirect(Location.SESSION_EXPIRED_PAGE)
public class SessionExpiredOidcRedirectFilter implements OidcRedirectFilter {

    @Override
    public void filter(OidcRedirectContext context) {

        if (!"tenant-refresh".equals(context.oidcTenantConfig().tenantId.get())) {
            throw new RuntimeException("Invalid tenant id");
        }

        if (!context.redirectUri().contains("/session-expired-page")) {
            throw new RuntimeException("Invalid redirect URI");
        }

        AuthorizationCodeTokens tokens = context.routingContext().get(AuthorizationCodeTokens.class.getName());
        String userName = OidcCommonUtils.decodeJwtContent(tokens.getIdToken()).getString(Claims.preferred_username.name());
        String jwe = Jwt.preferredUserName(userName).jwe()
                .encryptWithSecret(context.oidcTenantConfig().credentials.secret.get());
        OidcUtils.createCookie(context.routingContext(), context.oidcTenantConfig(), "session_expired",
                jwe + "|" + context.oidcTenantConfig().tenantId.get(), 10);

        context.additionalQueryParams().add("session-expired", "true");
    }

}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Scope the filter to the intended tenant (e.g. register it only for tenant-refresh via tenant-specific configuration)
  2. Update the tenant-id comparison to match the actual configured tenant id
  3. Verify quarkus.oidc.<tenant>.tenant-id in application.properties matches 'tenant-refresh'

Example fix

// before
if (!"tenant-refresh".equals(context.oidcTenantConfig().tenantId.get())) {
    throw new RuntimeException("Invalid tenant id");
}
// after
if (!"tenant-refresh".equals(context.oidcTenantConfig().tenantId.get())) {
    // skip instead of failing for other tenants
    return;
}
Defensive patterns

Strategy: validation

Validate before calling

String tenantId = context.oidcTenantConfig().tenantId.get();
if (!"tenant-refresh".equals(tenantId)) {
    return; // skip unrelated tenants instead of throwing
}

Try / catch

try {
    redirectFilter.filter(context);
} catch (RuntimeException e) {
    if (e.getMessage().equals("Invalid tenant id")) {
        // filter applied to wrong tenant; scope its registration
    }
}

Prevention

When it happens

Trigger: The filter is registered globally (via @OidcRedirectFilter or config) and an OIDC redirect is produced for a tenant other than 'tenant-refresh'.

Common situations: Multiple OIDC tenants configured but the filter not scoped to one tenant; filter class picked up for all redirects; renaming tenant ids in application.properties without updating the filter.

Related errors


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