quarkusio/quarkus · error · OIDCException
OIDC tenants '%s' and '%s' share the same back-channel logou
Error message
OIDC tenants '%s' and '%s' share the same back-channel logout path '%s', which is not supported
What it means
When two OIDC tenants (static or dynamic) resolve to the same back-channel logout path, the path matcher cannot route a logout callback to a unique tenant. The handler throws OIDCException (after logging an error) unless the duplicate comes from a previous config identical to the current tenant id.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/BackChannelLogoutHandler.java:127
String routePath = getTenantLogoutPath(configContext);
if (routePath.contains("*")) {
throw new IllegalStateException("Back-channel logout path cannot contain a wildcard '*' character");
}
OidcTenantConfig previousConfig = pathCache.put(routePath, configContext.oidcConfig());
tenantIdCache.add(configContext.oidcConfig().tenantId().get());
if (previousConfig == null) {
Handler<RoutingContext> routeHandler = new RouteHandler(configContext, resolver);
builder.addPath(routePath, routeHandler);
} else {
String previousTenantId = previousConfig.tenantId().get();
String currentTenantId = configContext.oidcConfig().tenantId().get();
// maybe invalid state, but technically it could happen that some produces a static tenant with
// a same id as a dynamic tenant
if (!previousTenantId.equals(currentTenantId)) {
String errorMessage = "OIDC tenants '%s' and '%s' share the same back-channel logout path '%s', which is not supported"
.formatted(previousTenantId, currentTenantId, routePath);
LOG.error(errorMessage);
throw new OIDCException(errorMessage);
}
}
}
}
if (builder != null) {
pathMatcher = builder.build();
} else {
pathMatcher = null;
}
return tenantIdCache;
}
private String getTenantLogoutPath(TenantConfigContext tenant) {
return OidcUtils.getRootPath(resolver.getRootPath()) + tenant.oidcConfig().logout().backchannel().path().orElse(null);
}
private static final class RouteHandler implements Handler<RoutingContext> {
private final TenantConfigContext tenantContext;View on GitHub (pinned to e1c734241f)
Solutions
- Give each tenant a unique back-channel logout path (e.g. prefix with tenant id)
- Remove or merge the duplicate tenant configuration
- If a dynamic tenant duplicates a static tenant intentionally, ensure ids match, otherwise fix the path
Example fix
// before quarkus.oidc.tenant-a.logout.backchannel-path=/back-channel-logout quarkus.oidc.tenant-b.logout.backchannel-path=/back-channel-logout // after quarkus.oidc.tenant-a.logout.backchannel-path=/tenant-a/back-channel-logout quarkus.oidc.tenant-b.logout.backchannel-path=/tenant-b/back-channel-logout
Defensive patterns
Strategy: validation
Validate before calling
Set<String> paths = new HashSet<>();
for (tenant : allTenants) {
String p = tenant.logout().backchannel().path().orElse(DEFAULT);
if (!paths.add(p)) throw new IllegalStateException("Duplicate back-channel logout path: " + p);
} Try / catch
try { handler.createPathMatcher(); } catch (OIDCException e) { if (e.getMessage().contains("share the same back-channel logout path")) { /* make paths unique per tenant */ } } Prevention
- Prefix logout paths with tenant id in multi-tenant setups
- Keep a registry test asserting path uniqueness
- Watch startup logs for the LOG.error emitted before the exception
When it happens
Trigger: Two tenants whose back-channel logout paths (or default paths) are equal — e.g. tenant-a and tenant-b both configured with the same backchannel-path — while building the path matcher via createPathMatcher/currentTenantIds.
Common situations: Copy-pasting tenant config and leaving the same logout path; a dynamic tenant registered at runtime that collides with a static tenant's path.
Related errors
- Back-channel logout path cannot contain a wildcard '*' chara
- Annotation '%s' placed on '%s' specifies no 'acr' value
- The '%s' annotation is only supported when proactive authent
- Tenant configuration has not been resolved
- %s OidcClient can not complete the %s grant request because
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/1bd33891b9e9ec3c.
Report an issue: GitHub.