KEYCLOAK - Setting a fixed issuer value

February 27, 2024

Tags: #keycloak #issuer

Keycloak derieves the issuer value, used in the openid-configuration document and in generated tokens, from the hostname settings of the server. This is not wrong and a valid decision made by the team some time ago. While one is not forced to do so, it’s totally ok to use the hostname as a valid issuer value.

Sometimes, this comes to a downside and you need or want to set a fixed issuer value in your Keyccloak server. E.g. when your realm is available through different hostnames, for whatever reason. But setting a fixed or custom value is not possible by default, as the responsible method to create the issuer value, is a static method in the org.keycloak.services.Urls utility class. So, that’s also a… well, decision.

I had the challenge to solve exactly this - setting a custom and fixed issuer value for a realm, no matter how (through which hostname) it is accessed. After some fiddling around, I found a solution with some - some may say “dirty” hack - bytecode modification and overriding the respective method at server startup with my own logic to return the desired issuer value.

Use bytecode modification only if there's no other way, at your own risk and only if you know what you are doing!!!

After all, this was easier as thought - Keycloak already uses ByteBuddy for internal bytecode modification, so I “just” had to add the ByteBuddy Agent, so that I’m able to replace methods during runtime. I implemented this with the help of my custom Initializer SPI, which allows me to do some operations and modifications in Keycloak only on startup, without the need to “misuse” one of the regular SPIs. My IssuerInitializerProvider reads the config, if there is a setting for the issuer in the init() method, then, during postInit() I’m replacing the default Urls.realmIssuer() static method with my custom implementation, see below. Works like a charm and has minimal to no drawbacks during runtime, as only during startup the bytecode modification is done, nothing else during runtime! Yes, bytecode modification can be dangerous, so always be sure what you do, don’t use it inflationary!

public static String realmIssuer(URI baseUri, String realmName) {
  try {
    baseUri = new URI(issuerBaseUri); // <-- set issuerBaseUri through configuration
  } catch (URISyntaxException | NullPointerException ignored) {
  }
  return Urls.realmBase(baseUri).path("{realm}").build(realmName).toString();
}

It's an often-seen anti-pattern: Never misuse existing SPIs for something else, they are all there for a purpose. Create your own SPI, it's easy! See e.g. my above mentioned Initializer SPI

Du bist auf der Suche nach Keycloak Beratung, Unterstützung, Workshops oder Trainings?

Nimm Kontakt mit mir auf!

« KEYCLOAK - Flushing and clear Realm and User Caches via Admin REST API