quarkusio/quarkus · error · io.quarkus.runtime.configuration.ConfigurationException
Both public key and certificate chain verification modes are
Error message
Both public key and certificate chain verification modes are enabled
What it means
A tenant may verify tokens with either a locally configured public key or a certificate-chain trust store, but not both — they are alternative offline verification modes and using both is contradictory. TenantContextFactory.createTenantContext throws this ConfigurationException when, for a tenant with no auth-server-url, both quarkus.oidc.public-key and quarkus.oidc.certificate-chain.trust-store-file are set.
Source
Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/TenantContextFactory.java:180
LOG.debugf(
"'%s' tenant is not initialized: '%s'. Access to resources protected by this tenant will fail.",
tenantId, t.getMessage());
return t;
}
@SuppressWarnings("resource")
private Uni<TenantConfigContext> createTenantContext(OidcTenantConfig oidcTenantConfig,
boolean checkNamedTenants, String tenantId) {
final OidcTenantConfig oidcConfig = OidcUtils.resolveProviderConfig(oidcTenantConfig);
if (!oidcConfig.tenantEnabled()) {
LOG.debugf("'%s' tenant configuration is disabled", tenantId);
return TenantConfigContext.createReady(new OidcProvider(null, null, null), oidcConfig);
}
if (oidcConfig.authServerUrl().isEmpty()) {
if (oidcConfig.publicKey().isPresent() && oidcConfig.certificateChain().trustStoreFile().isPresent()) {
throw new ConfigurationException("Both public key and certificate chain verification modes are enabled");
}
if (oidcConfig.publicKey().isPresent()) {
return createTenantContextFromPublicKey(oidcConfig);
}
if (oidcConfig.certificateChain().trustStoreFile().isPresent()) {
return createTenantContextToVerifyCertChain(oidcConfig);
}
}
try {
if (oidcConfig.authServerUrl().isEmpty()) {
if (DEFAULT_TENANT_ID.equals(oidcConfig.tenantId().get())) {
ArcContainer container = Arc.container();
if (container != null
&& (container.instance(TenantConfigResolver.class).isAvailable() || checkNamedTenants)) {
LOG.debugf("Default tenant is not configured and will be disabled"
+ " because either 'TenantConfigResolver' which will resolve tenant configurations is registered"View on GitHub (pinned to e1c734241f)
Solutions
- Remove the quarkus.oidc.public-key property if you intend to verify with the certificate chain trust store.
- Remove the quarkus.oidc.certificate-chain.trust-store-file property (and related cert-chain settings) if you intend to verify with the public key.
- If you actually meant to talk to an OIDC provider, set quarkus.oidc.auth-server-url and remove both offline verification options.
Example fix
// before (application.properties) quarkus.oidc.public-key=MIIBIjANBg... quarkus.oidc.certificate-chain.trust-store-file=/etc/certs/ca.p12 // after quarkus.oidc.certificate-chain.trust-store-file=/etc/certs/ca.p12
Defensive patterns
Strategy: validation
Validate before calling
boolean publicKeySet = System.getProperty("quarkus.oidc.public-key") != null;
boolean chainSet = System.getProperty("quarkus.oidc.certificate-chain.trust-store-file") != null;
if (publicKeySet && chainSet) {
throw new IllegalStateException("Choose either public-key or certificate-chain verification, not both");
} Prevention
- When migrating verification modes, grep config files for leftover quarkus.oidc.public-key or certificate-chain entries.
- Document per-environment which offline verification mode is used.
- Avoid combining env-var config overlays that can enable both modes simultaneously.
When it happens
Trigger: Creating a tenant context for a tenant without auth-server-url where both oidcConfig.publicKey().isPresent() and oidcConfig.certificateChain().trustStoreFile().isPresent() — i.e. both quarkus.oidc.public-key and quarkus.oidc.certificate-chain.trust-store-file (tenant-scoped variants included) are configured.
Common situations: Switching from public-key verification to certificate-chain verification but leaving the old public-key property behind; merging tenant config from two sources (application.properties + profile/env) so both modes end up enabled; a shared config template containing both keys.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Neither public key nor certificate chain verification modes
- Dynamic tenant ID cannot be same as the default tenant ID: %
- '%s' property must be configured
- UserInfo is not required but UserInfo is expected to be the
- UserInfo is not required but '%s' is enabled
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/bffbd17917871188.
Report an issue: GitHub.