quarkusio/quarkus · error · OidcClientException

%s OidcClient can not complete the %s grant request because

Error message

%s OidcClient can not complete the %s grant request because a %s client_assertion is missing

What it means

This OidcClientException is thrown by OidcClientImpl.preparePostRequest when the client is configured to authenticate with a JWT client assertion (client_credentials or jwt-based credentials), but no assertion could be produced. The assertion normally comes from a configured JWT source (key/certificate/token-path) or a client assertion provider; when both are missing the token request cannot be built.

Source

Thrown at extensions/oidc-client/runtime/src/main/java/io/quarkus/oidc/client/runtime/OidcClientImpl.java:230

            request.putHeader(AUTHORIZATION_HEADER, clientSecretBasicAuthScheme);
            if (hasClientSecretProvider()) {
                credentialsToRetry = PreparedPostRequest.CredentialsToRetry.CLIENT_SECRET_BASIC_AUTH_SCHEME;
            }
        } else if (jwtAssertionProvided) {
            String clientAssertion = additionalGrantParameters.get(OidcConstants.CLIENT_ASSERTION);
            if (clientAssertion == null) {
                clientAssertion = asyncCredentials.clientAssertion;
                if (clientAssertion != null) {
                    body.set(OidcConstants.CLIENT_ASSERTION, clientAssertion);
                }
            }
            if (clientAssertion == null) {
                String errorMessage = String.format(
                        "%s OidcClient can not complete the %s grant request because a %s client_assertion is missing",
                        oidcConfig.id().get(), (isRefresh(op) ? OidcConstants.REFRESH_TOKEN_GRANT : grantType),
                        OidcCommonUtils.getClientAssertionTokenType(oidcConfig.credentials().jwt().source()));
                LOG.error(errorMessage);
                throw new OidcClientException(errorMessage);
            }
            body.set(OidcConstants.CLIENT_ASSERTION_TYPE,
                    clientAssertionProvider != null ? clientAssertionProvider.getClientAssertionType()
                            : OidcConstants.JWT_BEARER_CLIENT_ASSERTION_TYPE);
        } else if (clientJwtKey != null) {
            // if it is a refresh then a map has already been copied
            body = !isRefresh(op) ? copyMultiMap(body) : body;
            String jwt = OidcCommonUtils.signJwtWithKey(oidcConfig, tokenRequestUri, clientJwtKey);

            if (OidcCommonUtils.isClientSecretPostJwtAuthRequired(oidcConfig.credentials())) {
                body.add(OidcConstants.CLIENT_ID, oidcConfig.clientId().get());
                body.add(OidcConstants.CLIENT_SECRET, jwt);
            } else if (OidcCommonUtils.isJwtAssertion(oidcConfig.credentials())) {
                if (!OidcConstants.JWT_BEARER_GRANT_TYPE.equals(body.get(OidcConstants.GRANT_TYPE))) {
                    String errorMessage = String.format(
                            "%s OidcClient wants to use JWT bearer grant assertion but has a wrong grant type %s configured."
                                    + " You must set 'quarkus.oidc-client.grant.type' property to 'jwt'.",
                            oidcConfig.id().get(), body.get(OidcConstants.GRANT_TYPE));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Set quarkus.oidc-client.credentials.jwt.key, key-store, or token-path so a client_assertion can be produced
  2. If using a custom client assertion provider, ensure it returns a non-null assertion
  3. If JWT client assertion is not intended, remove/reconfigure quarkus.oidc-client.credentials.jwt.source (e.g. use client-secret instead)
  4. Verify the configured keystore file exists and is readable at runtime

Example fix

# before
quarkus.oidc-client.credentials.jwt.source=key
# (no key configured -> assertion missing)

# after
quarkus.oidc-client.credentials.jwt.source=key
quarkus.oidc-client.credentials.jwt.key-location=classpath:privateKey.pem
Defensive patterns

Strategy: validation

Validate before calling

if (config.credentials().jwt().source() != JwtSource.NONE && config.credentials().jwt().keyStore().isEmpty() && config.credentials().jwt().key().isEmpty() && config.credentials().jwt().tokenPath().isEmpty()) {
    throw new IllegalArgumentException("JWT source configured but no key/key-store/token-path set for OIDC client " + config.id().orElse(""));
}

Type guard

boolean hasClientAssertionMaterial(OidcClientConfig c) {
    return c.credentials().jwt().key().isPresent() || c.credentials().jwt().keyStore().isPresent() || c.credentials().jwt().tokenPath().isPresent();
}

Try / catch

try { tokens = client.getTokens().await().indefinitely(); } catch (OidcClientException e) { if (e.getMessage().contains("client_assertion is missing")) { log.error("Fix credentials.jwt config", e); } throw e; }

Prevention

When it happens

Trigger: Calling getTokens/refreshTokens on an OidcClient whose quarkus.oidc-client.credentials.jwt.source implies a client_assertion but no JWT source material is available — e.g. credentials.jwt.source=key with no key store configured, or a token-path that yields nothing, or a client assertion provider returning null.

Common situations: Setting quarkus.oidc-client.credentials.client-secret-path/jwt settings partially (source configured but key file missing); migrating from client-secret to JWT auth and forgetting the keystore; configuring assertion providers that fail to initialize at runtime.

Related errors


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