diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index 932fd097fb628..c6e0226ad6735 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -868,6 +868,16 @@
quarkus-oidc-client-reactive-filter-deployment
${project.version}
+
+ io.quarkus
+ quarkus-oidc-client-graphql
+ ${project.version}
+
+
+ io.quarkus
+ quarkus-oidc-client-graphql-deployment
+ ${project.version}
+
io.quarkus
quarkus-oidc-token-propagation
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java
index 6e8d59d8fd423..cebff1c71face 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java
@@ -71,6 +71,7 @@ public enum Feature {
OIDC_CLIENT,
OIDC_CLIENT_FILTER,
OIDC_CLIENT_REACTIVE_FILTER,
+ OIDC_CLIENT_GRAPHQL_CLIENT_INTEGRATION,
OIDC_TOKEN_PROPAGATION,
OIDC_TOKEN_PROPAGATION_REACTIVE,
OPENSHIFT_CLIENT,
diff --git a/devtools/bom-descriptor-json/pom.xml b/devtools/bom-descriptor-json/pom.xml
index 22c2cca510f18..cbdbc050e4dfc 100644
--- a/devtools/bom-descriptor-json/pom.xml
+++ b/devtools/bom-descriptor-json/pom.xml
@@ -1565,6 +1565,19 @@
+
+ io.quarkus
+ quarkus-oidc-client-graphql
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
io.quarkus
quarkus-oidc-client-reactive-filter
diff --git a/docs/pom.xml b/docs/pom.xml
index d28aa46df1760..38070aa3d12c1 100644
--- a/docs/pom.xml
+++ b/docs/pom.xml
@@ -1581,6 +1581,19 @@
+
+ io.quarkus
+ quarkus-oidc-client-graphql-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
io.quarkus
quarkus-oidc-client-reactive-filter-deployment
diff --git a/docs/src/main/asciidoc/security-openid-connect-client-reference.adoc b/docs/src/main/asciidoc/security-openid-connect-client-reference.adoc
index f875bc2f8931a..3689c193715b5 100644
--- a/docs/src/main/asciidoc/security-openid-connect-client-reference.adoc
+++ b/docs/src/main/asciidoc/security-openid-connect-client-reference.adoc
@@ -1117,6 +1117,42 @@ The `quarkus-oidc-token-propagation-reactive` extension provides `io.quarkus.oid
The `quarkus-oidc-token-propagation-reactive` extension (as opposed to the non-reactive `quarkus-oidc-token-propagation` extension) does not currently support the exchanging or resigning the tokens before the propagation.
However, these features may be added in the future.
+[[oidc-client-graphql-client]]
+== GraphQL client integration
+
+The `quarkus-oidc-client-graphql` extension provides a way to integrate an
+OIDC client into GraphQL clients. This works similarly as with REST clients.
+When this extension is present, any configured (that means NOT created
+programmatically via the builder, but via configuration properties) GraphQL
+client will attempt to use the OIDC client to obtain the value of the
+`Authorization` header.
+
+To configure which OIDC client should be used by GraphQL clients, use
+
+----
+quarkus.oidc-client-graphql.client-name=OIDC_CLIENT_NAME
+----
+
+For typesafe GraphQL clients, you can override this on a per-client basis by annotating
+the `GraphQLClientApi` interface with `@OidcClientFilter("OIDC_CLIENT_NAME")`.
+
+To be able to use this with a programmatically created GraphQL client, both
+builders (`VertxDynamicGraphQLClientBuilder` and
+`VertxTypesafeGraphQLClientBuilder`) contain a method `dynamicHeader(String,
+Uni`) that allows you to plug in a header that might change for
+every request. To plug an OIDC client into it, use
+
+```
+@Inject
+OidcClients oidcClients;
+
+VertxTypesafeGraphQLClientBuilder builder = ....;
+Uni tokenUni = clients.getClient("OIDC_CLIENT_NAME")
+ .getTokens().map(t -> "Bearer " + t.getAccessToken());
+builder.dynamicHeader("Authorization", tokenUni);
+... = builder.build();
+```
+
== References
* xref:security-openid-connect-client.adoc[OpenID Connect Client and Token Propagation Quickstart]
diff --git a/extensions/oidc-client-graphql/deployment/pom.xml b/extensions/oidc-client-graphql/deployment/pom.xml
new file mode 100644
index 0000000000000..ec964b1a93152
--- /dev/null
+++ b/extensions/oidc-client-graphql/deployment/pom.xml
@@ -0,0 +1,128 @@
+
+
+
+ quarkus-oidc-client-graphql-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ quarkus-oidc-client-graphql-deployment
+ Quarkus - OpenID Connect Client GraphQL integration - Deployment
+
+
+
+ io.quarkus
+ quarkus-core-deployment
+
+
+ io.quarkus
+ quarkus-arc-deployment
+
+
+ io.quarkus
+ quarkus-oidc-client-graphql
+
+
+ io.quarkus
+ quarkus-oidc-client-deployment
+
+
+ io.quarkus
+ quarkus-smallrye-graphql-client-deployment
+
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+ io.quarkus
+ quarkus-test-keycloak-server
+ test
+
+
+ junit
+ junit
+
+
+
+
+ io.quarkus
+ quarkus-oidc-deployment
+ test
+
+
+ io.quarkus
+ quarkus-smallrye-graphql-deployment
+ test
+
+
+ io.quarkus
+ quarkus-resteasy-reactive-deployment
+ test
+
+
+
+
+
+
+ src/test/resources
+ true
+
+
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
+
+ test-keycloak
+
+
+ test-containers
+
+
+
+
+
+ maven-surefire-plugin
+
+ false
+
+ ${keycloak.docker.legacy.image}
+ false
+
+
+
+
+
+
+
+
diff --git a/extensions/oidc-client-graphql/deployment/src/main/java/io/quarkus/oidc/client/graphql/OidcGraphQLClientIntegrationProcessor.java b/extensions/oidc-client-graphql/deployment/src/main/java/io/quarkus/oidc/client/graphql/OidcGraphQLClientIntegrationProcessor.java
new file mode 100644
index 0000000000000..5cc32a72e59c1
--- /dev/null
+++ b/extensions/oidc-client-graphql/deployment/src/main/java/io/quarkus/oidc/client/graphql/OidcGraphQLClientIntegrationProcessor.java
@@ -0,0 +1,57 @@
+package io.quarkus.oidc.client.graphql;
+
+import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.AnnotationValue;
+import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.DotName;
+
+import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem;
+import io.quarkus.arc.deployment.BeanContainerBuildItem;
+import io.quarkus.deployment.Feature;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.oidc.client.graphql.runtime.OidcClientGraphQLConfig;
+import io.quarkus.oidc.client.graphql.runtime.OidcGraphQLClientIntegrationRecorder;
+
+public class OidcGraphQLClientIntegrationProcessor {
+
+ private static final DotName GRAPHQL_CLIENT_API = DotName
+ .createSimple("io.smallrye.graphql.client.typesafe.api.GraphQLClientApi");
+
+ private static final String OIDC_CLIENT_FILTER = "io.quarkus.oidc.client.filter.OidcClientFilter";
+
+ @BuildStep
+ void feature(BuildProducer featureProducer) {
+ featureProducer.produce(new FeatureBuildItem(Feature.OIDC_CLIENT_GRAPHQL_CLIENT_INTEGRATION));
+ }
+
+ @BuildStep
+ @Record(RUNTIME_INIT)
+ void initialize(BeanContainerBuildItem containerBuildItem,
+ OidcGraphQLClientIntegrationRecorder recorder,
+ OidcClientGraphQLConfig config,
+ BeanArchiveIndexBuildItem index) {
+ Map configKeysToOidcClients = new HashMap<>();
+ for (AnnotationInstance annotation : index.getIndex().getAnnotations(GRAPHQL_CLIENT_API)) {
+ ClassInfo clazz = annotation.target().asClass();
+ AnnotationInstance oidcClient = clazz.annotation(OIDC_CLIENT_FILTER);
+ if (oidcClient != null) {
+ String oidcClientName = oidcClient.valueWithDefault(index.getIndex(), "value").asString();
+ AnnotationValue configKeyValue = annotation.value("configKey");
+ String configKey = configKeyValue != null ? configKeyValue.asString() : null;
+ String actualConfigKey = (configKey != null && !configKey.equals("")) ? configKey : clazz.name().toString();
+ if (oidcClientName != null && !oidcClientName.isEmpty()) {
+ configKeysToOidcClients.put(actualConfigKey, oidcClientName);
+ }
+ }
+ }
+ recorder.enhanceGraphQLClientConfigurationWithOidc(configKeysToOidcClients, config.clientName.orElse(null));
+ }
+}
diff --git a/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/AnnotationTypesafeGraphQLClient.java b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/AnnotationTypesafeGraphQLClient.java
new file mode 100644
index 0000000000000..e598ce5f6f50d
--- /dev/null
+++ b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/AnnotationTypesafeGraphQLClient.java
@@ -0,0 +1,15 @@
+package io.quarkus.oidc.client.graphql;
+
+import org.eclipse.microprofile.graphql.Query;
+
+import io.quarkus.oidc.client.filter.OidcClientFilter;
+import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi;
+
+@GraphQLClientApi(configKey = "typesafe-annotation")
+@OidcClientFilter("annotation")
+public interface AnnotationTypesafeGraphQLClient {
+
+ @Query
+ String principalName();
+
+}
diff --git a/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/DefaultTypesafeGraphQLClient.java b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/DefaultTypesafeGraphQLClient.java
new file mode 100644
index 0000000000000..630c360e77bce
--- /dev/null
+++ b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/DefaultTypesafeGraphQLClient.java
@@ -0,0 +1,15 @@
+package io.quarkus.oidc.client.graphql;
+
+import org.eclipse.microprofile.graphql.Query;
+
+import io.quarkus.oidc.client.filter.OidcClientFilter;
+import io.smallrye.graphql.client.typesafe.api.GraphQLClientApi;
+
+@GraphQLClientApi(configKey = "typesafe-default")
+@OidcClientFilter
+public interface DefaultTypesafeGraphQLClient {
+
+ @Query
+ String principalName();
+
+}
diff --git a/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/GraphQLClientResource.java b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/GraphQLClientResource.java
new file mode 100644
index 0000000000000..5fdb09359dfea
--- /dev/null
+++ b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/GraphQLClientResource.java
@@ -0,0 +1,43 @@
+package io.quarkus.oidc.client.graphql;
+
+import java.util.concurrent.ExecutionException;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+
+import io.smallrye.graphql.client.GraphQLClient;
+import io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClient;
+
+@Path("/oidc-graphql-client")
+public class GraphQLClientResource {
+
+ @Inject
+ AnnotationTypesafeGraphQLClient annotationTypesafeClient;
+
+ @Inject
+ DefaultTypesafeGraphQLClient defaultTypesafeClient;
+
+ @GET
+ @Path("/annotation-typesafe")
+ public String typesafeClientAnnotation() {
+ return annotationTypesafeClient.principalName();
+ }
+
+ @GET
+ @Path("/default-typesafe")
+ public String typesafeClientDefault() {
+ return defaultTypesafeClient.principalName();
+ }
+
+ @Inject
+ @GraphQLClient("default-dynamic")
+ DynamicGraphQLClient dynamicClient;
+
+ @GET
+ @Path("/default-dynamic")
+ public String dynamicClientDefault() throws ExecutionException, InterruptedException {
+ return dynamicClient.executeSync("query { principalName }").getData().getString("principalName");
+ }
+
+}
diff --git a/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/GraphQLClientUsingOidcClientTest.java b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/GraphQLClientUsingOidcClientTest.java
new file mode 100644
index 0000000000000..112fb47baf5cb
--- /dev/null
+++ b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/GraphQLClientUsingOidcClientTest.java
@@ -0,0 +1,62 @@
+package io.quarkus.oidc.client.graphql;
+
+import static org.hamcrest.Matchers.equalTo;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.test.QuarkusDevModeTest;
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.keycloak.server.KeycloakTestResourceLifecycleManager;
+import io.restassured.RestAssured;
+
+@QuarkusTestResource(KeycloakTestResourceLifecycleManager.class)
+public class GraphQLClientUsingOidcClientTest {
+
+ private static final Class>[] testClasses = {
+ ProtectedResource.class,
+ GraphQLClientResource.class,
+ AnnotationTypesafeGraphQLClient.class,
+ DefaultTypesafeGraphQLClient.class
+ };
+
+ @RegisterExtension
+ static final QuarkusDevModeTest test = new QuarkusDevModeTest()
+ .withApplicationRoot((jar) -> jar
+ .addClasses(testClasses)
+ .addAsResource("application.properties", "application.properties"));
+
+ @Test
+ public void typesafeClientAnnotation() {
+ // OidcClient selected via @OidcClient("clientName")
+ RestAssured.when().get("/oidc-graphql-client/annotation-typesafe")
+ .then()
+ .statusCode(200)
+ .body(equalTo("jdoe"));
+ }
+
+ @Test
+ public void typesafeClientWithDefault() {
+ // OidcClient selected via @OidcClient without a value - this should resort to the default client
+ RestAssured.when().get("/oidc-graphql-client/default-typesafe")
+ .then()
+ .statusCode(200)
+ .body(equalTo("alice"));
+ // just to make sure it works more than once
+ RestAssured.when().get("/oidc-graphql-client/default-typesafe")
+ .then()
+ .statusCode(200)
+ .body(equalTo("alice"));
+ }
+
+ @Test
+ public void dynamicClientWithDefault() {
+ // dynamic clients should always resort to the default (`quarkus.oidc-client-graphql.client-name`),
+ // because currently we don't have a way to override it
+ RestAssured.when().get("/oidc-graphql-client/default-dynamic")
+ .then()
+ .statusCode(200)
+ .body(equalTo("alice"));
+ }
+
+}
diff --git a/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/ProtectedResource.java b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/ProtectedResource.java
new file mode 100644
index 0000000000000..93f8bb23230ba
--- /dev/null
+++ b/extensions/oidc-client-graphql/deployment/src/test/java/io/quarkus/oidc/client/graphql/ProtectedResource.java
@@ -0,0 +1,23 @@
+package io.quarkus.oidc.client.graphql;
+
+import java.security.Principal;
+
+import jakarta.inject.Inject;
+
+import org.eclipse.microprofile.graphql.GraphQLApi;
+import org.eclipse.microprofile.graphql.Query;
+
+import io.quarkus.security.Authenticated;
+
+@GraphQLApi
+@Authenticated
+public class ProtectedResource {
+
+ @Inject
+ Principal principal;
+
+ @Query
+ public String principalName() {
+ return principal.getName();
+ }
+}
diff --git a/extensions/oidc-client-graphql/deployment/src/test/resources/application.properties b/extensions/oidc-client-graphql/deployment/src/test/resources/application.properties
new file mode 100644
index 0000000000000..721c8e9ab2883
--- /dev/null
+++ b/extensions/oidc-client-graphql/deployment/src/test/resources/application.properties
@@ -0,0 +1,27 @@
+quarkus.oidc.auth-server-url=${keycloak.url}/realms/quarkus/
+quarkus.oidc.client-id=quarkus-service-app
+quarkus.oidc.credentials.secret=secret
+
+quarkus.oidc-client.annotation.auth-server-url=${quarkus.oidc.auth-server-url}
+quarkus.oidc-client.annotation.client-id=${quarkus.oidc.client-id}
+quarkus.oidc-client.annotation.credentials.client-secret.value=${quarkus.oidc.credentials.secret}
+quarkus.oidc-client.annotation.credentials.client-secret.method=POST
+quarkus.oidc-client.annotation.grant.type=password
+quarkus.oidc-client.annotation.grant-options.password.username=jdoe
+quarkus.oidc-client.annotation.grant-options.password.password=jdoe
+
+quarkus.oidc-client.configured-default.auth-server-url=${quarkus.oidc.auth-server-url}
+quarkus.oidc-client.configured-default.client-id=${quarkus.oidc.client-id}
+quarkus.oidc-client.configured-default.credentials.client-secret.value=${quarkus.oidc.credentials.secret}
+quarkus.oidc-client.configured-default.credentials.client-secret.method=POST
+quarkus.oidc-client.configured-default.grant.type=password
+quarkus.oidc-client.configured-default.grant-options.password.username=alice
+quarkus.oidc-client.configured-default.grant-options.password.password=alice
+
+# FIXME: avoid hardcoding the URL
+quarkus.smallrye-graphql-client.typesafe-annotation.url=http://localhost:8080/graphql
+quarkus.smallrye-graphql-client.typesafe-default.url=http://localhost:8080/graphql
+quarkus.smallrye-graphql-client.default-dynamic.url=http://localhost:8080/graphql
+
+# default OIDC client for GraphQL clients
+quarkus.oidc-client-graphql.client-name=configured-default
\ No newline at end of file
diff --git a/extensions/oidc-client-graphql/pom.xml b/extensions/oidc-client-graphql/pom.xml
new file mode 100644
index 0000000000000..6f85166404778
--- /dev/null
+++ b/extensions/oidc-client-graphql/pom.xml
@@ -0,0 +1,20 @@
+
+
+
+ quarkus-extensions-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ quarkus-oidc-client-graphql-parent
+ Quarkus - OpenID Connect Client GraphQL integration
+ pom
+
+ deployment
+ runtime
+
+
diff --git a/extensions/oidc-client-graphql/runtime/pom.xml b/extensions/oidc-client-graphql/runtime/pom.xml
new file mode 100644
index 0000000000000..0fd99ca208623
--- /dev/null
+++ b/extensions/oidc-client-graphql/runtime/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ quarkus-oidc-client-graphql-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ quarkus-oidc-client-graphql
+ Quarkus - OpenID Connect Client GraphQL integration - Runtime
+ Use GraphQL client and get and refresh access tokens with OpenId Connect Client and send them as HTTP Authorization Bearer tokens
+
+
+ io.quarkus
+ quarkus-core
+
+
+ io.quarkus
+ quarkus-arc
+
+
+ io.quarkus
+ quarkus-oidc-client
+
+
+ io.quarkus
+ quarkus-smallrye-graphql-client
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+
+
+
+
+ io.quarkus
+ quarkus-extension-maven-plugin
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
diff --git a/extensions/oidc-client-graphql/runtime/src/main/java/io/quarkus/oidc/client/graphql/runtime/OidcClientGraphQLConfig.java b/extensions/oidc-client-graphql/runtime/src/main/java/io/quarkus/oidc/client/graphql/runtime/OidcClientGraphQLConfig.java
new file mode 100644
index 0000000000000..7a78cd7137009
--- /dev/null
+++ b/extensions/oidc-client-graphql/runtime/src/main/java/io/quarkus/oidc/client/graphql/runtime/OidcClientGraphQLConfig.java
@@ -0,0 +1,18 @@
+package io.quarkus.oidc.client.graphql.runtime;
+
+import java.util.Optional;
+
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot(name = "oidc-client-graphql", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
+public class OidcClientGraphQLConfig {
+
+ /**
+ * Name of the configured OidcClient used by GraphQL clients. You can override this configuration
+ * for typesafe clients with the `io.quarkus.oidc.client.filter.OidcClientFilter` annotation.
+ */
+ @ConfigItem
+ public Optional clientName;
+}
diff --git a/extensions/oidc-client-graphql/runtime/src/main/java/io/quarkus/oidc/client/graphql/runtime/OidcGraphQLClientIntegrationRecorder.java b/extensions/oidc-client-graphql/runtime/src/main/java/io/quarkus/oidc/client/graphql/runtime/OidcGraphQLClientIntegrationRecorder.java
new file mode 100644
index 0000000000000..38a8ebc9dcb6c
--- /dev/null
+++ b/extensions/oidc-client-graphql/runtime/src/main/java/io/quarkus/oidc/client/graphql/runtime/OidcGraphQLClientIntegrationRecorder.java
@@ -0,0 +1,44 @@
+package io.quarkus.oidc.client.graphql.runtime;
+
+import java.util.Map;
+
+import io.quarkus.arc.Arc;
+import io.quarkus.oidc.client.OidcClients;
+import io.quarkus.oidc.client.Tokens;
+import io.quarkus.runtime.annotations.Recorder;
+import io.smallrye.graphql.client.impl.GraphQLClientsConfiguration;
+import io.smallrye.mutiny.Uni;
+
+@Recorder
+public class OidcGraphQLClientIntegrationRecorder {
+
+ public void enhanceGraphQLClientConfigurationWithOidc(Map configKeysToOidcClients,
+ String defaultOidcClientName) {
+ OidcClients oidcClients = Arc.container().instance(OidcClients.class).get();
+ GraphQLClientsConfiguration configs = GraphQLClientsConfiguration.getInstance();
+ configs.getClients().forEach((graphQLClientKey, value) -> {
+ String oidcClient = configKeysToOidcClients.get(graphQLClientKey);
+ if (oidcClient == null) {
+ oidcClient = defaultOidcClientName;
+ }
+ Map> dynamicHeaders = configs.getClient(graphQLClientKey).getDynamicHeaders();
+ dynamicHeaders.put("Authorization", getToken(oidcClients, oidcClient));
+ });
+ }
+
+ public Uni getToken(OidcClients clients, String oidcClientId) {
+ Uni tokenUni = clients.getClient("MY_OIDC_CLIENT").getTokens().map(t -> "Bearer " + t.getAccessToken());
+ if (oidcClientId == null) {
+ return clients.getClient()
+ .getTokens()
+ .map(Tokens::getAccessToken)
+ .map(token -> "Bearer " + token);
+ } else {
+ return clients.getClient(oidcClientId)
+ .getTokens()
+ .map(Tokens::getAccessToken)
+ .map(token -> "Bearer " + token);
+ }
+ }
+
+}
diff --git a/extensions/oidc-client-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/oidc-client-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000000000..33682cd9a1adf
--- /dev/null
+++ b/extensions/oidc-client-graphql/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,16 @@
+---
+artifact: ${project.groupId}:${project.artifactId}:${project.version}
+name: "OpenID Connect Client integration for GraphQL client"
+metadata:
+ keywords:
+ - "oauth2"
+ - "openid-connect"
+ - "oidc"
+ - "oidc-client"
+ - "graphql-client"
+ guide: "https://quarkus.io/guides/security-openid-connect-client"
+ categories:
+ - "security"
+ status: "experimental"
+ config:
+ - "quarkus.oidc-client."
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 746699977266a..5734b8bde14df 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -139,6 +139,7 @@
oidc-client
oidc-client-filter
oidc-client-reactive-filter
+ oidc-client-graphql
oidc-token-propagation
oidc-token-propagation-reactive
oidc-db-token-state-manager
diff --git a/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java b/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java
index b74277457375d..7fec562a3f912 100644
--- a/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java
+++ b/extensions/smallrye-graphql-client/deployment/src/main/java/io/quarkus/smallrye/graphql/client/deployment/SmallRyeGraphQLClientProcessor.java
@@ -170,7 +170,8 @@ void initializeClientSupport(BuildProducer syntheticBean
shortNamesToQualifiedNames.put(clazz.name().withoutPackagePrefix(), clazz.name().toString());
AnnotationValue configKeyValue = annotation.value("configKey");
String configKey = configKeyValue != null ? configKeyValue.asString() : null;
- knownConfigKeys.add((configKey != null && !configKey.equals("")) ? configKey : clazz.name().toString());
+ String actualConfigKey = (configKey != null && !configKey.equals("")) ? configKey : clazz.name().toString();
+ knownConfigKeys.add(actualConfigKey);
}
for (AnnotationInstance annotation : index.getIndex().getAnnotations(GRAPHQL_CLIENT)) {
@@ -181,7 +182,8 @@ void initializeClientSupport(BuildProducer syntheticBean
knownConfigKeys.add(configKey);
}
- RuntimeValue support = recorder.clientSupport(shortNamesToQualifiedNames, knownConfigKeys);
+ RuntimeValue support = recorder.clientSupport(shortNamesToQualifiedNames,
+ knownConfigKeys);
DotName supportClassName = DotName.createSimple(GraphQLClientSupport.class.getName());
SyntheticBeanBuildItem bean = SyntheticBeanBuildItem
diff --git a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfigurationMergerBean.java b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfigurationMergerBean.java
index 840b244746a53..ac23a5b57b453 100644
--- a/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfigurationMergerBean.java
+++ b/extensions/smallrye-graphql-client/runtime/src/main/java/io/quarkus/smallrye/graphql/client/runtime/GraphQLClientConfigurationMergerBean.java
@@ -115,6 +115,7 @@ private GraphQLClientConfiguration toSmallRyeNativeConfiguration(GraphQLClientCo
.ifPresent(transformed::setExecuteSingleOperationsOverWebsocket);
quarkusConfig.websocketInitializationTimeout.ifPresent(transformed::setWebsocketInitializationTimeout);
quarkusConfig.allowUnexpectedResponseFields.ifPresent(transformed::setAllowUnexpectedResponseFields);
+ transformed.setDynamicHeaders(new HashMap<>());
return transformed;
}
diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/complex/GraphQLFederationComplexTest.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/complex/GraphQLFederationComplexTest.java
index c102cc31d8f19..9481279424f6d 100644
--- a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/complex/GraphQLFederationComplexTest.java
+++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/federation/complex/GraphQLFederationComplexTest.java
@@ -2,8 +2,6 @@
import static org.hamcrest.Matchers.containsString;
-import jakarta.inject.Inject;
-
import org.hamcrest.CoreMatchers;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.asset.StringAsset;