Quarkus GraphQL Client with Keycloak

Viewed 316

I'm trying this for days right now and I'm not sure if i missed something.

I have a Quarkus GraphQL Service , like here : https://quarkus.io/guides/smallrye-graphql

And I have setup Keycloak to secure it.

Now I wanted to create a client with Qute and GraphQL Smallrye client like here : https://quarkus.io/guides/smallrye-graphql-client

The client can connect to the service, but I always get an "Data Fetching Error: io.quarkus.security.UnauthorizedException".

It seems like the GraphQL client is not sending the headers correctly or it doesn't send any ...

Does anyone know how I can tell the client to send the Authorization header from keycloak with every call?

PS: I tested it with a short react frontend and there it's working, so it seems to be an graphql client issue with the headers... Some ideas?

2 Answers

Not sure if you're using a dynamic or typesafe client, so I'll describe both.

For both types, if you have a key that doesn't change during the life of the application, you can configure that by adding a configuration property like this: quarkus.smallrye-graphql-client.CLIENT_NAME.header.HEADER_NAME=HEADER_VALUE (see https://quarkus.io/guides/all-config#quarkus-smallrye-graphql-client_quarkus-smallrye-graphql-client-smallrye-graphql-client)

If the value can change over time, I would probably recommend using the programmatic builder instead of using a statically configured client, like this:

DynamicGraphQLClientBuilder.newBuilder()
   .header("KEY", "VALUE") // obtain the correct value from Keycloak and pass it here
.... 

and build a new client instance if the value changes.

For typesafe clients, an annotation-based way is described in https://smallrye.io/smallrye-graphql/1.4.3/typesafe-client-headers/

I don't know much about Keycloak though so I can't comment on the way how you obtain the header value from it. Let me know some of this works for you

There doesn't seem to be a dynamic way of adding keycloak headers to the call.

I found a solution, to at least work as long as the token is valid.

For this I'm using a Client Class, which has an Interface Object of the GraphQL client and injects the header inside the constructor.I will need to add some code to renew the token, but it's enough to work with it right now :)

For those who want some code:

@Singleton
public class Client {

    public IClient client;

    public Client(JsonWebToken accessToken) {
        client = TypesafeGraphQLClientBuilder.newBuilder()
                .header("Authorization", "Bearer " + accessToken.getRawToken())
                .build(IClient.class);
    }
}

With this the Client can be build like shown at the Quarkus Guides :)

Related