quarkusio/quarkus · error · ConfigurationException

Only one of JWT secret or JWT private key authentication met

Error message

Only one of JWT secret or JWT private key authentication methods can be configured, but '%1$scredentials.jwt' has both a JWT secret and a JWT key property set

What it means

A JWT client assertion can be signed either with a secret (HMAC) or with a private key (RSA/EC), never both. verifyCommonConfiguration detects that credentials.jwt.secret (jwtSecretConfigured) and a JWT key property (jwtKeyConfigured) are both present and fails startup, because it could not decide which signing method to use for the client JWT.

Source

Thrown at extensions/oidc-common/runtime/src/main/java/io/quarkus/oidc/common/runtime/OidcCommonUtils.java:209

                                    + " but '%1$scredentials' has both a client secret and a JWT secret property set",
                            configPrefix));
        }
        int jwtKeyPropsCount = (creds.jwt().key().isPresent() ? 1 : 0)
                + (creds.jwt().keyFile().isPresent() ? 1 : 0)
                + (creds.jwt().keyStoreFile().isPresent() ? 1 : 0);
        if (jwtKeyPropsCount > 1) {
            throw new ConfigurationException(
                    String.format(
                            "Only one of '%1$scredentials.jwt.key', '%1$scredentials.jwt.key-file'"
                                    + " or '%1$scredentials.jwt.key-store-file' can be configured",
                            configPrefix));
        }
        boolean jwtKeyConfigured = jwtKeyPropsCount == 1;
        boolean jwtBearerOrSpiffe = creds.jwt().source() == Source.BEARER
                || creds.jwt().source() == Source.SPIFFE_JWT;

        if (jwtSecretConfigured && jwtKeyConfigured) {
            throw new ConfigurationException(
                    String.format(
                            "Only one of JWT secret or JWT private key authentication methods can be configured,"
                                    + " but '%1$scredentials.jwt' has both a JWT secret and a JWT key property set",
                            configPrefix));
        }
        if (clientSecretConfigured && jwtKeyConfigured) {
            throw new ConfigurationException(
                    String.format(
                            "Only one of client secret or JWT private key authentication methods can be configured,"
                                    + " but '%1$scredentials' has both a client secret and a JWT key property set",
                            configPrefix));
        }
        if (clientSecretConfigured && jwtBearerOrSpiffe) {
            throw new ConfigurationException(
                    String.format(
                            "Only one of client secret or JWT bearer/SPIFFE authentication methods can be configured,"
                                    + " but '%1$scredentials' has both a client secret and '%1$scredentials.jwt.source=%2$s' set",
                            configPrefix, creds.jwt().source().toString().toLowerCase()));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Decide the auth method: if using private-key JWT, delete credentials.jwt.secret; if using secret JWT, delete the credentials.jwt.key* property
  2. Keep exactly one signing mechanism under the given quarkus.oidc[-client].credentials.jwt prefix
  3. Check environment variables/config source overrides that may inject the second property

Example fix

# before
quarkus.oidc-client.credentials.jwt.secret=shared-secret
quarkus.oidc-client.credentials.jwt.key-file=/etc/certs/key.pem

# after
quarkus.oidc-client.credentials.jwt.key-file=/etc/certs/key.pem
Defensive patterns

Strategy: validation

Validate before calling

boolean secret = ConfigProvider.getConfig().getOptionalValue("quarkus.oidc-client.credentials.jwt.secret", String.class).isPresent();
boolean key = ConfigProvider.getConfig().getOptionalValue("quarkus.oidc-client.credentials.jwt.key-file", String.class).isPresent();
if (secret && key) throw new IllegalStateException("Choose either jwt secret or jwt private key, not both");

Try / catch

try {
    start();
} catch (ConfigurationException e) {
    if (e.getMessage().contains("both a JWT secret and a JWT key")) log.error("Remove jwt.secret or the jwt key property");
    throw e;
}

Prevention

When it happens

Trigger: At startup, both a secret (credentials.jwt.secret) and one of credentials.jwt.key / key-file / key-store-file are set under the same config prefix in verifyCommonConfiguration.

Common situations: Adding a private key to a config that already used secret-based authentication (client_secret_jwt) for stronger security but forgetting to delete the secret; merging property files; a template config that includes both options.

Understand the failure class

Related errors


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