Changing Keycloak's appearance through themes: understanding the five theme types, the theme directory structure with FreeMarker templates and message bundles, plus branding and multi-language customization.

In episode 20 you tuned the realm, clients, and authentication flows. Episode 21 is about the side users see directly: themes. Keycloak's default login page is generic; by understanding the theme structure you can replace logos, colors, email templates, even add languages. Theme customization is also part of SSO service professionalism — users judge security by the appearance they trust.
Keycloak has five theme types, each for a different surface:
| Theme Type | Used for | Set at |
|---|---|---|
| Login | Login, register, password reset pages | Realm Settings → Themes |
| Account | User account pages (profile, sessions, password) | Realm Settings → Themes |
| Admin Console | Administrator interface | Admin console |
| Email templates (verify, reset password) | Realm Settings → Themes | |
| Welcome | Welcome page and initial admin creation | Server settings |
Note that the admin console and welcome themes are set at a different level from login/account/email — don't be surprised that changing the login theme doesn't change the admin console.
Themes live in the themes/ folder with one subfolder per type. For example themes/mytema/login/ for a custom login theme. Its core files:
| Contents | Description |
|---|---|
theme.properties | Theme metadata: parent, styles, import |
*.ftl | FreeMarker templates for pages |
styles.css | Page styling |
script.js | Additional JavaScript |
resources/ | Images and other assets |
messages/ | Message bundles for translations |
The most important key is parent. With parent=keycloak, your theme inherits the built-in templates so you don't need to rewrite everything:
parent=keycloak
import=common/keycloak
styles=css/styles.cssWhen the Keycloak version goes up, the inherited built-in templates get updated too — this is the reason to set parent rather than copying the entire theme.
The login pages are written as FreeMarker templates, such as login.ftl, register.ftl, and reset-password.ftl. Templates are where you change the HTML structure, not just the colors.
Start with the easiest: put a logo in resources/, then declare it in styles.css. Without changing templates, the visual identity changes immediately across all derived pages.
For structural changes, edit login.ftl or another template. When done, select the theme in Realm Settings → Themes and test it on the realm's login page.
Error pages (e.g. session expired or access denied) also have their own templates, such as error.ftl. Adjust them so error messages stay clear without leaking internal details.
The email theme contains FreeMarker templates like password-reset.ftl and email-verify.ftl. These determine the content of the password reset email discussed in episode 20 — important for branding and language.
Translations are stored as message bundles in messages/. Create messages_id.properties for your preferred language:
loginTitle=Sign in
loginAccountTitle=Sign in to your account
doLogin=Sign inKeycloak picks the bundle based on the user's browser locale. This way you add languages without touching a single template.
When themes alone aren't enough, Keycloak provides SPI (Service Provider Interface) for Java code extensions:
Providers are stored as JARs in the providers folder:
cp my-provider.jar keycloak/providers/
bin/kc.sh start-devWhen the server starts, Keycloak automatically loads JARs from that folder. Test the provider in a separate environment before touching production.
In episode 21, you understood Keycloak themes: the five theme types (login, account, admin console, email, welcome), the directory structure (theme.properties, FreeMarker templates, CSS, JavaScript, resources, message bundles), branding and multi-language customization, and advanced extensions through SPI.
Key takeaways:
parent=keycloak so themes are easy to maintain when the version goes up.In the next episode (episode 22), you'll make use of the activity trail: Events & Auditing — event types, event listeners, and how to record who signed in, who did what, and when.