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

  1. Remove the quarkus.oidc.public-key property if you intend to verify with the certificate chain trust store.
  2. Remove the quarkus.oidc.certificate-chain.trust-store-file property (and related cert-chain settings) if you intend to verify with the public key.
  3. 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 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

Related errors


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