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
- Decide the auth method: if using private-key JWT, delete credentials.jwt.secret; if using secret JWT, delete the credentials.jwt.key* property
- Keep exactly one signing mechanism under the given quarkus.oidc[-client].credentials.jwt prefix
- 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
- Document which auth method each service uses; never template both secret and key properties
- After migrating auth methods, diff and delete obsolete properties
- Audit env vars/config sources that may inject a second property
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Only one of client secret or JWT bearer/SPIFFE authenticatio
- Only one of JWT private key or JWT bearer/SPIFFE authenticat
- '%scredentials.jwt.token-path' must be set when the JWT sour
- ISSUED_AT_INVALID_PAST
- Cannot get token for tenant '%s' because a %s client_asserti
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/60f59ed0da9264f6.
Report an issue: GitHub.