quarkusio/quarkus · error · ConfigurationException

Token exchange is required but OIDC client is configured to

Error message

Token exchange is required but OIDC client is configured to use the <grantType> grantType

What it means

AccessTokenRequestFilter.initExchangeTokenClient validates that the OIDC client configured for token exchange uses a grant type capable of it. Only EXCHANGE (RFC 8693) and JWT bearer grants carry an incoming token/assertion; any other grantType cannot exchange, so a ConfigurationException is thrown.

Source

Thrown at extensions/oidc-token-propagation/runtime/src/main/java/io/quarkus/oidc/token/propagation/AccessTokenRequestFilter.java:64

    }

    @PostConstruct
    public void initExchangeTokenClient() {
        if (isExchangeToken()) {
            OidcClients clients = Arc.container().instance(OidcClients.class).get();
            String clientName = getClientName();
            exchangeTokenClient = clientName != null ? clients.getClient(clientName) : clients.getClient();
            Grant.Type exchangeTokenGrantType = ConfigProvider.getConfig()
                    .getValue(
                            "quarkus.oidc-client." + (clientName != null ? clientName + "." : "")
                                    + "grant.type",
                            Grant.Type.class);
            if (exchangeTokenGrantType == Grant.Type.EXCHANGE) {
                exchangeTokenProperty = OidcConstants.EXCHANGE_GRANT_SUBJECT_TOKEN;
            } else if (exchangeTokenGrantType == Grant.Type.JWT) {
                exchangeTokenProperty = OidcConstants.JWT_BEARER_GRANT_ASSERTION;
            } else {
                throw new ConfigurationException("Token exchange is required but OIDC client is configured "
                        + "to use the " + exchangeTokenGrantType.getGrantType() + " grantType");
            }
        }
    }

    protected boolean isExchangeToken() {
        return ConfigProvider.getConfig().getValue("quarkus.resteasy-client-oidc-token-propagation.exchange-token",
                boolean.class);
    }

    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        if (skipPropagation(requestContext)) {
            return;
        }

        if (acquireTokenCredentialFromCtx(requestContext)) {
            propagateToken(requestContext, exchangeTokenIfNeeded(getTokenCredentialFromContext().getToken()));

View on GitHub (pinned to e1c734241f)

Solutions

  1. Set the OIDC client grant type to 'exchange' for RFC 8693 token exchange
  2. Or use grant type 'jwt' (JWT bearer) if exchanging via a JWT assertion
  3. Use a dedicated OidcClient named for exchange and point the filter to it, instead of reusing a client-credentials client
  4. Confirm the authorization server supports the chosen grant type

Example fix

// before
quarkus.oidc-client.exchange-client.grant.type=client
// after
quarkus.oidc-client.exchange-client.grant.type=exchange
Defensive patterns

Strategy: validation

Validate before calling

OidcClientConfig client = clients.get("exchange-client");
Grant.Type t = client.grant().type().orElse(Grant.Type.CLIENT);
if (t != Grant.Type.EXCHANGE && t != Grant.Type.JWT) {
    throw new IllegalStateException("Token exchange needs grant.type=exchange or jwt, got: " + t);
}

Prevention

When it happens

Trigger: Token exchange is requested (exchange token configured on the OIDC client used by the filter) but the client's grant.type is something like 'client' (client credentials), 'password', or 'refresh' instead of 'exchange' or 'jwt'.

Common situations: Misconfigured quarkus.oidc-client.<name>.grant.type when wiring token exchange into REST client propagation; copying a client config that used client-credentials and trying to reuse it for exchange; authorization server not supporting the exchange grant leads to config drift.

Related errors


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