{"record":{"id":"d757e1b550619530","repo":"quarkusio/quarkus","slug":"token-exchange-is-required-but-oidc-client-is-conf","errorCode":null,"errorMessage":"Token exchange is required but OIDC client is configured to use the <grantType> grantType","messagePattern":"Token exchange is required but OIDC client is configured to use the <grantType> grantType","errorType":"validation","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"extensions/oidc-token-propagation/runtime/src/main/java/io/quarkus/oidc/token/propagation/AccessTokenRequestFilter.java","lineNumber":64,"sourceCode":"    }\n\n    @PostConstruct\n    public void initExchangeTokenClient() {\n        if (isExchangeToken()) {\n            OidcClients clients = Arc.container().instance(OidcClients.class).get();\n            String clientName = getClientName();\n            exchangeTokenClient = clientName != null ? clients.getClient(clientName) : clients.getClient();\n            Grant.Type exchangeTokenGrantType = ConfigProvider.getConfig()\n                    .getValue(\n                            \"quarkus.oidc-client.\" + (clientName != null ? clientName + \".\" : \"\")\n                                    + \"grant.type\",\n                            Grant.Type.class);\n            if (exchangeTokenGrantType == Grant.Type.EXCHANGE) {\n                exchangeTokenProperty = OidcConstants.EXCHANGE_GRANT_SUBJECT_TOKEN;\n            } else if (exchangeTokenGrantType == Grant.Type.JWT) {\n                exchangeTokenProperty = OidcConstants.JWT_BEARER_GRANT_ASSERTION;\n            } else {\n                throw new ConfigurationException(\"Token exchange is required but OIDC client is configured \"\n                        + \"to use the \" + exchangeTokenGrantType.getGrantType() + \" grantType\");\n            }\n        }\n    }\n\n    protected boolean isExchangeToken() {\n        return ConfigProvider.getConfig().getValue(\"quarkus.resteasy-client-oidc-token-propagation.exchange-token\",\n                boolean.class);\n    }\n\n    @Override\n    public void filter(ClientRequestContext requestContext) throws IOException {\n        if (skipPropagation(requestContext)) {\n            return;\n        }\n\n        if (acquireTokenCredentialFromCtx(requestContext)) {\n            propagateToken(requestContext, exchangeTokenIfNeeded(getTokenCredentialFromContext().getToken()));","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/oidc-token-propagation/runtime/src/main/java/io/quarkus/oidc/token/propagation/AccessTokenRequestFilter.java#L46-L82","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","solutions":["Set the OIDC client grant type to 'exchange' for RFC 8693 token exchange","Or use grant type 'jwt' (JWT bearer) if exchanging via a JWT assertion","Use a dedicated OidcClient named for exchange and point the filter to it, instead of reusing a client-credentials client","Confirm the authorization server supports the chosen grant type"],"exampleFix":"// before\nquarkus.oidc-client.exchange-client.grant.type=client\n// after\nquarkus.oidc-client.exchange-client.grant.type=exchange","handlingStrategy":"validation","validationCode":"OidcClientConfig client = clients.get(\"exchange-client\");\nGrant.Type t = client.grant().type().orElse(Grant.Type.CLIENT);\nif (t != Grant.Type.EXCHANGE && t != Grant.Type.JWT) {\n    throw new IllegalStateException(\"Token exchange needs grant.type=exchange or jwt, got: \" + t);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use grant.type=exchange (or jwt) for any client used for token exchange","Dedicate a separate named OIDC client to exchange, don't reuse client-credentials clients","Verify the IdP supports RFC 8693 token exchange"],"tags":["quarkus","oidc","token-exchange","configuration"],"backgroundTag":"invalid-grant-type","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"}