Keycloak is an open-source IAM solution that provides user federation, strong authentication, user management, and much more. As a single sign-on provider, it allows users to authenticate with Keycloak rather than individual applications via dedicated login forms. Such forms are often internationalized and require different layouts and language bundles to render properly, and Keycloak allows one to customize the locale selection and resolution rules as necessary.
In this post, we will look at options provided by Keycloak that allow a server developer to customize the locale resolution rules for various freemarker templates and HTML forms. Our starting position is as follows:
22
17
Keycloak documentation indicates that the default locale is English with the internationalization setting disabled. When this option is enabled, the locale is resolved according to the following logic:
ui_locales
parameter.Accept-Language
headerIf none of the above, fall back to English.
If the above selection does not immediately meet your needs, Keycloak also allows one to provide their locale selection logic via a dedicated implementation of the LocaleSelectorProvider
interface. These implementations can extend the DefaultLocaleSelectorProvider
to reuse, ignore or enhance parts of the default behavior.
To extend parts of Keycloak, one has to register custom implementations of Keycloak Service Provider Interfaces (SPIs). In our case, we will need to implement the org.keycloak.locale.LocaleSelectorProviderFactory
and register it with the Java Service Loader API. This factory is then tasked to supply an implementation of the LocaleSelectorProvider
that selects and delivers the final locale to Keycloak.
So, let’s start with our factory implementation:
package org.example.keycloak;
public class MyLocaleSelectorProviderFactory
extends DefaultLocaleSelectorProviderFactory {
@Override
public LocaleSelectorProvider create(KeycloakSession session) {
return new MyLocaleSelectorProvider(session);
}
@Override
public String getId() {
return "MyLocale";
}
}
…and then, our own MyLocaleSelectorProvider
implementation:
public class MyLocaleSelectorProvider extends DefaultLocaleSelectorProvider {
@Override
public Locale resolveLocale(RealmModel realm, UserModel user) {
// Stuff happens...
return ...;
}
}
Next, we need to register our factory implementation inside the file META-INF/services/org.keycloak.locale.LocaleSelectorProviderFactory
:
org.example.keycloak.MyLocaleSelectorProviderFactory
At this point, Keycloak has access to multiple options for selecting and loading locales. Ours, and what ships by default. So, we will need to instruct Keycloak to use our version of the locale selection rules and skip the default:
/path/to/keycloak/bin/kc.sh --build --spi-locale-selector-provider=MyLocale
The SPI identifier, MyLocale
, represents the identifier of the factory implementation as stated by the getId()
method.
If you have questions about the contents and the topic of this blog post, or if you need additional guidance and support, feel free to send us a note and ask about consulting and support services.
I hope this review was of some help to you and I am sure that both this post as well as the functionality it attempts to explain can be improved in any number of ways. Please feel free to engage and contribute as best as you can.
Happy Coding,
Monday-Friday
9am-6pm, Central European Time
7am-1pm, U.S. Eastern Time
Monday-Friday
9am-6pm, Central European Time