Automating Keycloak with Java

We needed to automate some tasks in our Keycloak so that some elements were created as events were happening.

I find that the Java library for Keycloak is not always intuitive. It does not help that my searches for the documentation or examples returned all sorts of contradicting results.

In this case adding an Identity Provider seems to have many ways to be done but only 1 worked for me.

What works:


Alternative code I had seen that I could not get to work for me:

var clientRes = client.updateRealm(destinationRealmResource.toRepresentation());

And this did not work for me:

var clientRes = client.updateRealm(destinationRealmResource.toRepresentation());

This was done with Keycloak 15.

In my troubleshooting I also noticed that having some invalid strings in your representation configuration can cause the creation to fail. I am not a fan of the Map<String, String> for the configuration because that leaves room for a lot of mistakes.

Keycloak Identity Provider ID

That took a couple of hours to figure out so let’s share some notes.

I have code that creates the required Keycloak Realms and configures a few items in each of them.

One of those configuration is to create the Identity Provider so that we can link users to another realm. Internal SSO if you will.

I tested this with Keycloak 11.0.3.

I did not understand that the Identity Provider ID needed to be one of the specific values since it is only a string that you pass to it. Sometimes I wish they could use an enum to help users make sense of it quickly.

After getting errors that it was a required fields and trying a few values that did not make sense to Keycloak.

10:39:07.587 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "{"errorMessage":"Invalid identity provider id [password]"}"

10:41:50.814 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "{"errorMessage":"Invalid identity provider id [EmailAuthProviderID]"}"

I tried keycloak-oidc and it worked. So the value needs to be one of these:

  • saml
  • oidc
  • keycloak-oidc

You could also use one of the social identity provider.

I also understood to take the config from the endpoint:

Sample code:

IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation();
Map<String, String> config = new HashMap<>();
config.put("issuer", "");
config.put("authorization_endpoint", "");
config.put("token_endpoint", "");
config.put("introspection_endpoint", "");
config.put("userinfo_endpoint", "");
config.put("end_session_endpoint", "");
config.put("jwks_uri", "");
config.put("check_session_iframe", "");
config.put("grant_types_supported", "[\"authorization_code\",\"implicit\",\"refresh_token\",\"password\",\"client_credentials\"]");
config.put("response_types_supported", "[\"code\",\"none\",\"id_token\",\"token\",\"id_token token\",\"code id_token\",\"code token\",\"code id_token token\"]");
config.put("subject_types_supported", "[\"public\",\"pairwise\"]");
config.put("id_token_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\"]");
config.put("id_token_encryption_alg_values_supported", "[\"RSA-OAEP\",\"RSA1_5\"]");
config.put("id_token_encryption_enc_values_supported", "[\"A256GCM\",\"A192GCM\",\"A128GCM\",\"A128CBC-HS256\",\"A192CBC-HS384\",\"A256CBC-HS512\"]");
config.put("userinfo_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\",\"none\"]");
config.put("request_object_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\",\"none\"]");
config.put("response_modes_supported", "[\"query\",\"fragment\",\"form_post\"]");
config.put("registration_endpoint", "");
config.put("token_endpoint_auth_methods_supported", "[\"private_key_jwt\",\"client_secret_basic\",\"client_secret_post\",\"tls_client_auth\",\"client_secret_jwt\"]");
config.put("token_endpoint_auth_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\"]");
config.put("claims_supported", "[\"aud\",\"sub\",\"iss\",\"auth_time\",\"name\",\"given_name\",\"family_name\",\"preferred_username\",\"email\",\"acr\"]");
config.put("claim_types_supported", "[\"normal\"]");
config.put("claims_parameter_supported", "false");
config.put("scopes_supported", "[\"openid\",\"offline_access\", \"profile\",\"email\",\"address\",\"phone\",\"roles\",\"web-origins\",\"microprofile-jwt\"]");
config.put("request_parameter_supported", "true");
config.put("request_uri_parameter_supported", "true");
config.put("code_challenge_methods_supported", "[\"plain\",\"S256\"]");
config.put("tls_client_certificate_bound_access_tokens", "true");

Finally, I have creation of the Identity Provider in my realm and I can link users to it.

No JDK 16 for Gradle 6

That was an annoying configuration where my project was using JDK 11 but I did not see that my Gradle settings were using JDK 16 and that kept giving me the error:

Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:

After I removed JDK 16 from my project, it pointed me to the fact that Gradle had no JDK configured. Hint.

Now that everything is using JDK 11, life is beautiful again in my IDE.

Installing OpenJDK 11 on macOS (again)

I have started to use SDKMan to simplify my life with installing and updating many software that I use regurlarly. Java is one of them. It is the simplest thing to install java with sdk man:

sdk i java 11.0.8.hs-adpt

As simple as that.

I can just use Java 11 from that point on. You can also install Java 8 and switch between both. Convenient when you have to maintain older software.

If I want to update to a new release, I simply have to type:

sdk ug java

Can it really get any easier?

I use the SDKMan on my linux laptop as well and it easily works on both.

I also manage gradle, spring-boot and spark with SDKMan so most of my coding tools are kept up to date with the same tool.

Apache Commons Configuration and Map

Until today, the Apache Commons Configuration was a very helpful tool as a quick configuration utility in many projects. For loading simple configuration item it is fine.

I was trying to find a way to store and read a Map to contain some configuration and there is was no easy way that I could find. I came up with a Krusty solution for now but I am hoping that I can find something more elegant.

GitHub Repo with example code.

Jackson and mapping fields

I was trying to use the api to query and map browsers to my custom object and I did not want to name my fields with agent_type, agent_name and agent_version.

Simple solution that I found on this page was to annotate my properties in the class with:


The mapping is happening automatically.

Very simple.

Using log4j for email alerts in an application

I want to explore how using log4j for email alerts in an application is feasible but how well it works in a real application.

The idea came from the fact that a team I work with change the rules for alerts on a regular basis based on the work and the situations they are caught in. It is clear that we have to stop changing the code to accommodate the new rules they give us.

Log4j is a possibility and I found this blog post that talks about it:

Impact of the scope on the maven assembly plugin

For a Spark project I needed to bundle some dependencies and I found a few Stackoverflow answers that explained to add this section to your pom.xml:


But once I packaged my application I ended up with a huge jar file. It contained everything the application needed.

My mistake was that the pom.xml did not contain the proper scope for each dependency and because of that they were all getting bundled into the jar.

Specified that a few were provided (provided) and it reduced the jar size considerably.

How a small missing piece can change other behaviours drastically.

jmap notes

If you search for how to get a memory dump for a java process many will recommend jmap.

On a server, jmap is the tool to use since jvisualvm requires some ui and that is rarely available in our setup.

The command to use is simple:

jmap -heap.format:b <pid>

The problem is that it “freezes” your java application as the heap is being dumped and when you have a process that uses a bit of memory it takes a long time (very long time). The app I tried to get information from was using 2.3 Gb and after 30 minutes it was not done writing to the heap.bin. Had to abandon.