Search code examples
javakeycloakquarkusresteasy

Keycloak Provider and JAX-RS Client?


I have the need to call a REST endpoint after a user account is created in Keycloak (specifically, Keycloak 22.x). To accomplish this, I have implemented a Keycloak EventListenerProvider that listens for the appropriate event. As a PoC I had my EventListenerProvider simply log the event. Once I confirmed that was working, I started trying to use a JAX-RS Client Proxy to call my REST endpoint. However, I'm getting some exceptions when making the call. Here's what I've done...

My JAX-RS Client Proxy interface is built using Quarkus 3.2.4, simply because the rest of my code (and Keycloak, for that matter) uses Quarkus. It looks something like this:

@Path("/")
@RegisterRestClient
public interface MyClientProxy {

    @Path("/api/v1/admin/{realmIdentifier}/users/{userIdentifier}")
    @PUT
    @Consumes({ MediaType.APPLICATION_JSON })
    @Produces({ MediaType.APPLICATION_JSON })
    public Response createUserProfile(@PathParam("realmIdentifier") String realmIdentifier,
            @PathParam("userIdentifier") String userIdentifier, CreateUserProfileRequest request);

}

From there, my EventListenerProvider instantiates the proxy as follows:

String baseURI = ...
UriBuilder ub = UriBuilder.fromPath(baseURI);
ResteasyClient client = (ResteasyClient) ClientBuilder.newClient();
ResteasyWebTarget target = client.target(ub);

MyClientProxy proxy = target.proxy(MyClientProxy);

However, when my EventListenerProvider tries to call createUserProfile I see the following Exception in the Keycloak logs:

2023-08-23 18:43:16,929 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-5) Uncaught server error: java.lang.RuntimeException: java.lang.ClassNotFoundException: Provider for jakarta.ws.rs.client.ClientBuilder cannot be found

My initial assumption is that Resteasy was not included. My Maven build uses maven-shade-plugin to build a fat JAR, so I added an include line to ensure that org.jboss.resteasy:* would be included in the fat JAR. That led to a different Exception, though:

[error]: Build step io.quarkus.resteasy.deployment.ResteasyStandaloneBuildStep#staticInit threw an exception: java.lang.LinkageError: loader constraint violation: loader io.quarkus.bootstrap.classloading.QuarkusClassLoader @e36bb2a wants to load interface org.jboss.resteasy.spi.ResteasyDeployment. A different interface with the same name was previously loaded by java.net.URLClassLoader @37c7595. (org.jboss.resteasy.spi.ResteasyDeployment is in unnamed module of loader java.net.URLClassLoader @37c7595, parent loader 'app')

I've never seen that one before, so I'm not sure what's going on here. Any idea what could be the problem? I'm sure I'm missing something minor, but I can't pin down what.


Solution

  • Solved! After modifying the includes statement for maven-shade-plugin everything works properly. The new includes statement looks like this:

    <includes>
      <include>org.jboss.resteasy:resteasy-client</include>
      <include>org.jboss.resteasy:resteasy-client-api</include>
    </includes>
    

    The resteasy-client classes are not present in Keycloak and were missing from my fat JAR. After making this change I no longer ran into any problems.