{"record":{"id":"3932a6d3e4d365d5","repo":"quarkusio/quarkus","slug":"cannot-get-token-for-tenant-s-because-a-s-clie","errorCode":null,"errorMessage":"Cannot get token for tenant '%s' because a %s client_assertion is not available","messagePattern":"Cannot get token for tenant '(.+?)' because a (.+?) client_assertion is not available","errorType":"exception","errorClass":"io.quarkus.oidc.runtime.OIDCException","httpStatus":null,"severity":"error","filePath":"extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClientImpl.java","lineNumber":436,"sourceCode":"\n        if (!clientSecretQueryAuthentication) {\n            request.putHeader(CONTENT_TYPE_HEADER, APPLICATION_X_WWW_FORM_URLENCODED);\n            request.putHeader(ACCEPT_HEADER, APPLICATION_JSON);\n\n            if (isIntrospection(op) && introspectionBasicAuthScheme != null) {\n                request.putHeader(AUTHORIZATION_HEADER, introspectionBasicAuthScheme);\n                if (oidcConfig.clientId().isPresent() && oidcConfig.introspectionCredentials().includeClientId()) {\n                    formBody.set(OidcConstants.CLIENT_ID, oidcConfig.clientId().get());\n                }\n            } else if (clientSecretBasicAuthScheme != null) {\n                request.putHeader(AUTHORIZATION_HEADER, clientSecretBasicAuthScheme);\n                if (hasClientSecretProvider()) {\n                    credentialsToRetry = PreparedHttpRequest.CredentialsToRetry.CLIENT_SECRET_BASIC_AUTH_SCHEME;\n                }\n            } else if (jwtAssertionProvided) {\n                final String clientAssertion = asyncCredentials.clientAssertion;\n                if (clientAssertion == null) {\n                    throw new OIDCException(String.format(\n                            \"Cannot get token for tenant '%s' because a %s client_assertion is not available\",\n                            oidcConfig.tenantId().get(),\n                            OidcCommonUtils.getClientAssertionTokenType(oidcConfig.credentials().jwt().source())));\n                }\n                formBody.add(OidcConstants.CLIENT_ASSERTION, clientAssertion);\n                formBody.add(OidcConstants.CLIENT_ASSERTION_TYPE, clientAssertionProvider.getClientAssertionType());\n            } else if (clientJwtKey != null) {\n                String jwt = OidcCommonUtils.signJwtWithKey(oidcConfig, metadata.getTokenUri(), clientJwtKey);\n                if (OidcCommonUtils.isClientSecretPostJwtAuthRequired(oidcConfig.credentials())) {\n                    formBody.add(OidcConstants.CLIENT_ID, oidcConfig.clientId().get());\n                    formBody.add(OidcConstants.CLIENT_SECRET, jwt);\n                } else {\n                    formBody.add(OidcConstants.CLIENT_ASSERTION_TYPE, OidcConstants.JWT_BEARER_CLIENT_ASSERTION_TYPE);\n                    formBody.add(OidcConstants.CLIENT_ASSERTION, jwt);\n                }\n            } else if (OidcCommonUtils.isClientSecretPostAuthRequired(oidcConfig.credentials())) {\n                formBody.add(OidcConstants.CLIENT_ID, oidcConfig.clientId().get());\n                formBody.add(OidcConstants.CLIENT_SECRET, clientSecret);","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClientImpl.java#L418-L454","documentation":"Thrown by OidcProviderClientImpl.prepareHttpRequest while building a token-request form body when the configuration declares a JWT client assertion (credentials.jwt.source set, jwtAssertionProvided=true) but the asynchronously-fetched clientAssertion string is null at request time. The token endpoint call cannot be authenticated without the assertion, so an OIDCException naming the tenant and assertion type is thrown.","triggerScenarios":"A token request (code-to-token, refresh, etc.) for a tenant whose credentials use a client JWT assertion, and AsyncCredentials.clientAssertion has not been populated — typically because the assertion provider failed to produce or refresh the assertion before the HTTP request was sent.","commonSituations":" Misconfigured quarkus.oidc.credentials.jwt.* (e.g. missing key store, key file, or secret used to sign the assertion); assertion fetch from an external secret manager failing silently; race where the assertion expired and regeneration failed; using jwt.source=assertion without supplying the assertion.","solutions":["Check quarkus.oidc.credentials.jwt configuration completeness: key, key-file, key-store-file, or secret must be valid and loadable at startup","Look for earlier startup/log errors from the assertion provider (secret manager, key store) that left clientAssertion null","If jwt.source=assertion, ensure the assertion is actually supplied/refreshed by the integration in use","Test with credentials.jwt.source=client or secret-based auth to isolate whether the assertion pipeline is the problem"],"exampleFix":"# before: no signing material configured\nquarkus.oidc.credentials.jwt.source=assertion\n# after: supply key material\nquarkus.oidc.credentials.jwt.key-file=/secrets/client-key.pem\nquarkus.oidc.credentials.jwt.key-id=client-key\nquarkus.oidc.credentials.jwt.signature-algorithm=RS256","handlingStrategy":"validation","validationCode":"// before issuing token requests, assert the client assertion credential is resolvable\nif (config.credentials().jwt().source() != null && config.credentials().jwt().key().isEmpty()\n    && config.credentials().jwt().keyFile().isEmpty()\n    && config.credentials().jwt().keyStoreFile().isEmpty()) {\n    throw new IllegalStateException(\"JWT assertion source configured but no signing key material\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return oidcProvider.getToken(...);\n} catch (OIDCException e) {\n    if (e.getMessage().contains(\"client_assertion is not available\")) {\n        // refresh assertion credentials then retry once\n        asyncCredentials.refresh();\n        return oidcProvider.getToken(...);\n    }\n    throw e;\n}","preventionTips":["Validate credentials.jwt.* config at startup (fail fast if key material missing)","Monitor secret-manager/key-store health if assertions come from external sources","Set assertion TTLs with margin so renewal happens before expiry"],"tags":["oidc","client-assertion","jwt","configuration"],"backgroundTag":"missing-client-assertion","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}