Upgrading Keycloak

This guide describes how to upgrade Keycloak. Use the following procedures in this order:

  1. Review the migration changes from the previous version of Keycloak.

  2. Upgrade the Keycloak server.

  3. Upgrade the Keycloak adapters.

  4. Upgrade the Keycloak Admin Client.

Migration Changes

Migrating to 25.0.3

Concurrent login requests are blocked by default when brute force is enabled

If an attacker launched many login attempts in parallel then the attacker could have more guesses at a password than the brute force protection configuration permits. This was due to the brute force check occurring before the brute force protector has locked the user. To prevent this race the Brute Force Protector now rejects all login attempts that occur while another login is in progress in the same server.

If, for whatever reason, the new feature wants to be disabled there is a startup factory option:

bin/kc.[sh|bat] start --spi-brute-force-protector-default-brute-force-detector-allow-concurrent-requests=true

Migrating to 25.0.2

Improving performance for deletion of user consents

When a client scope or the full realm are deleted the associated user consents should also be removed. A new index over the table USER_CONSENT_CLIENT_SCOPE has been added to increase the performance.

Note that, if the table contains more than 300.000 entries, by default Keycloak skips the creation of the indexes during the automatic schema migration and logs the SQL statements to the console instead. The statements must be run manually in the DB after Keycloak’s startup. Check the Upgrading Guide for details on how to configure a different limit.

Migrating to 25.0.0

New Hostname options

Hostname v2 options are supported by default, as the old hostname options are deprecated and will be removed in the following releases. New options are activated by default, so Keycloak will not recognize the old options.

List of necessary migrations:

Old options New options

hostname <hostname>
hostname-url <url>
hostname-path <path>
hostname-port <port>

hostname <hostname/url>

hostname-admin <hostname>
hostname-admin-url <url>

hostname-admin <url>

hostname-strict-backchannel <true/false>

hostname-backchannel-dynamic <true/false>

As you can see, the *-url suffixes were removed for hostname and hostname-admin options. Option hostname accepts both hostname and URL, but hostname-admin accepts only full URL now.

Additionally, there is no way to set path or port separately. You can achieve it by providing the full URL for the hostname and hostname-admin options.

If the port is not part of the URL, it is dynamically resolved from the incoming request headers.

HTTPS is no longer enforced unless it is part of hostname and hostname-admin URLs. If not specified, the used protocol (http/https) is dynamically resolved from the incoming request. The hostname-strict-https option is removed.

Removed options

hostname-url

hostname-admin-url

hostname-path

hostname-port

hostname-strict-backchannel

hostname-strict-https

In order to use the old hostname options to have more time for migration, turn on the feature hostname:v1, e.g. features=hostname:v1. Be aware, that either hostname:v1 or hostname:v2 can be enabled, not both at the same time.
Examples
Simplified notation
# Hostname v1
bin/kc.[sh|bat] start --hostname=mykeycloak.org --https-port=8543 --hostname-path=/auth --hostname-strict-https=true

# Hostname v2
bin/kc.[sh|bat] start --hostname=https://mykeycloak.org:8543/auth

As you can see in the example, all the parts of a URL can be now specified via single hostname option, which simplifies the hostname setup process. Notice that HTTPS is not enforced by the hostname-strict-https option, but by specifying it in the hostname URL.

Backchannel setting
# Hostname v1
bin/kc.[sh|bat] start --hostname=mykeycloak.org --hostname-strict-backchannel=true

# Hostname v2
bin/kc.[sh|bat] start --hostname=mykeycloak.org --hostname-backchannel-dynamic=false

Be aware that there is a change in behavior if the same URL is to be used for both backend and frontend endpoints. Previously, in hostname v1, the backchannel URL was dynamically resolved from request headers. Therefore, to achieve the required results, you had to specify the hostname-strict-backchannel=true.

For hostname v2, the backchannel URLs are already the same as the frontend ones. In order to dynamically resolve it from request headers, you need to set the hostname-backchannel-dynamic=true and provide a full URL for the hostname option.

For more details and more comprehensive scenarios, see Configuring the hostname (v2).

Persistent user sessions

Previous versions of Keycloak stored only offline user and offline client sessions in the databases. The new feature persistent-user-sessions stores online user sessions and online client sessions not only in memory, but also in the database. This will allow a user to stay logged in even if all instances of Keycloak are restarted or upgraded.

Enabling persistent user sessions

The feature is a preview feature and disabled by default. To use it, add the following to your build command:

bin/kc.sh build --features=persistent-user-sessions ...

For more details see the Enabling and disabling features guide. The sizing guide contains a new paragraph describing the updated resource requirements when this feature is enabled.

If this feature is enabled for an existing deployment that is using only the embedded Infinispan for storing sessions, the existing online user and client sessions will not be migrated to the database. It will only affect newly created online user and online client sessions.

With persistent sessions enabled, the in-memory caches for online user sessions, offline user sessions, online client sessions and offline client sessions are limited to 10000 entries per node by default which will reduce the overall memory usage of Keycloak for larger installations. Items which are evicted from memory will be loaded on-demand from the database when needed. To set different sizes for the caches, edit Keycloak’s cache config file to set a <memory max-count="..."/> for those caches. Once this feature is enabled, expect an increased database utilization on each login, logout and refresh token request.

To configure the cache size in an external Infinispan in a Keycloak multi-site setup, consult the updated Deploy Infinispan for HA with the Infinispan Operator guide.

With this feature enabled, the options spi-user-sessions-infinispan-offline-session-cache-entry-lifespan-override and spi-user-sessions-infinispan-offline-client-session-cache-entry-lifespan-override are no longer available, as they were previously used to override the time offline sessions were kept in-memory.

Migrating user sessions during the upgrade

When upgrading from Keycloak 24 or earlier, admins can choose to migrate existing online user and client sessions to persistent sessions. For this to work, those existing sessions need to be stored in either a remote Infinispan or in a database configured as JDBC persistence for Keycloak’s embedded cache. Migrating in-memory sessions for Keycloak 24 is not supported as all Keycloak instances need to be shut down before the upgrade due to a major version upgrade of the embedded Infinispan.

The migration of user sessions only works when the persistent user sessions is enabled when upgrading to Keycloak 25. If you chose to upgrade to 25 without enabling persistent user sessions, there is currently no possibility to trigger the migration of existing sessions at a later point in time.

Enabling this feature later, by a configuration change, can result in an undefined behavior of Keycloak related to sessions if both persisted and non-persisted sessions co-exist. To prevent that, remove all existing online user and client sessions before the first node is started with the feature enabled. This means all Keycloak nodes need to be stopped and, if used, Infinispan remote cache store and embedded Infinispan JDBC persistence need to be cleared.

To migrate the user sessions during an upgrade of Keycloak, perform the following steps:

  1. Stop all running old instances of Keycloak.

  2. Create backups:

    • Create a backup Keycloak’s database.

    • If JDBC persistence is used, create a backup of that database if you want to be able to retry the migration of the sessions.

    • If an external Infinispan is used, create a backup of its data if you want to be able to retry the migration of the sessions.

  3. Start the new instances Keycloak with the persistent user sessions feature enabled.

    The first starting node will:

    1. Migrate the database to the schema version 25.

    2. Copy all session information from either the remote Infinispan or the JDBC persistence configured for Keycloak’s embedded cache to the database of Keycloak.

      The data will be stored in the tables offline_user_session and offline_client_session with offline_flag set to false.

    3. Clear the caches.

      This includes clearing the caches of the external Infinispan if one is used, and clearing the JDBC persistence if one is used.

  4. Update the cache configuration XML of Keycloak for caches sessions and clientSessions:

    • If JDBC persistence is used, remove the configuration for JDBC persistence.

    • If the remote Infinispan has been used in a single-site setup solely for keeping user sessions across Keycloak restarts, remove the remote Infinispan configuration for those caches.

    If the remote Infinispan is used in a multi-site setup, you can reduce the resource consumption by the external Infinispan by configuring the number of entries in memory. Use the settings outlined in Deploy Infinispan for HA with the Infinispan Operator guide.
  5. Rolling restart of Keycloak to activate the new cache configuration XML.

Signing out existing users

In previous versions and when the feature is disabled, a restart of all Keycloak nodes logged out all users. To sign out all online users sessions of a realm with the persistent-user-sessions feature enabled, use the following steps as before:

  1. Log in to the Admin Console.

  2. Select the menu entry Sessions.

  3. Select the action Sign out all active sessions.

Metrics for embedded caches enabled by default

Metrics for the embedded caches are now enabled by default. To enable histograms for latencies, set the option cache-metrics-histograms-enabled to true.

Metrics for HTTP endpoints enabled by default

The metrics provided by Keycloak now include HTTP server metrics starting with http_server. See below for some examples.

http_server_active_requests 1.0
http_server_requests_seconds_count{method="GET",outcome="SUCCESS",status="200",uri="/realms/{realm}/protocol/{protocol}/auth"} 1.0
http_server_requests_seconds_sum{method="GET",outcome="SUCCESS",status="200",uri="/realms/{realm}/protocol/{protocol}/auth"} 0.048717142

Use the new options http-metrics-histograms-enabled and http-metrics-slos to enable default histogram buckets or specific buckets for service level objectives (SLOs). Read more about histograms in the Prometheus documentation about histograms on how to use the additional metrics series provided in http_server_requests_seconds_bucket.

Argon2 password hashing

In Keycloak 24 release, we had a change in the password hashing algorithm which resulted in an increased CPU usage. To address that, we opted to a different default hashing algorithm Argon2 for non-FIPS environments which brings the CPU usage back to where it was prior to the Keycloak 24 release.

Expected improvement in overall CPU usage and temporary increased database activity

The Concepts for sizing CPU and memory resources in the Keycloak High Availability guide have been updated to reflect the new hashing defaults.

After the upgrade, during a password-based login, the user’s passwords will be re-hashed with the new hash algorithm and hash iterations as a one-off activity and updated in the database. As this clears the user from Keycloak’s internal cache, you’ll also see an increased read activity on the database level. This increased database activity will decrease over time as more and more user’s passwords have been re-hashed.

Updated JVM garbage collection settings

To support the memory intensive nature of Argon2, we have updated the default GC from ParallelGC to G1GC for a better heap utilization. Please monitor the JVM heap utilization closely after this upgrade. Additional tuning may be necessary depending on your specific workload.

Limiting memory usage when consuming HTTP responses

In some scenarios like brokering Keycloak uses HTTP to talk to external servers. To avoid a denial of service when those providers send too much data, Keycloak now restricts responses to 10 MB by default.

Users can configure this limit by setting the provider configuration option spi-connections-http-client-default-max-consumed-response-size:

Restricting the consumed responses to 1 MB
bin/kc.[sh|bat] --spi-connections-http-client-default-max-consumed-response-size=1000000

Hostname Verification Policy

The default for spi-truststore-file-hostname-verification-policy and the new tls-hostname-verifier option is now DEFAULT, rather than WILDCARD. The WILDCARD and STRICT option values have been deprecated - you should simply rely upon DEFAULT instead.

Behavior supported by WILDCARD, that is not supported by DEFAULT: * allows wildcards in subdomain names (e.g. *.foo.com) to match anything, including multiple levels (e.g. a.b.foo.com). * allows matching against well known public suffixes - e.g. foo.co.gl may match *.co.gl

Behavior supported by STRICT, that is not supported by DEFAULT: * STRICT uses a small exclusion list for 2 or 3 letter domain names ending in a 2 letter top level (*.XXX.YY) when determining if a wildcard matches. Instead DEFAULT uses a more complete list of public suffix rules and exclusions from https://publicsuffix.org/list/

It is not expected that you should be relying upon these behaviors from the WILDCARD or STRICT options.

Addressed 'You are already logged in' for expired authentication sessions

Keycloak now does not display the message You are already logged in to the end user when an authentication session expires and user is already logged-in. Instead it redirects the error about the expired authentication session to the client application, so the client can act on it and restart authentication as described in the Server Administration Guide authentication sessions chapter. You may consider updating your applications to being able to handle this error.

Removed a model module

The module org.keycloak:keycloak-model-legacy module was deprecated in a previous release and is removed in this release. Use the org.keycloak:keycloak-model-storage module instead.

XA Transaction Changes

  • The option transaction-xa-enabled will default to false, rather than true. If you want XA transaction support you will now need to explicitly set this option to true.

  • XA Transaction recovery support is enabled by default if transaction-xa-enabled is true. Transaction logs will be stored at KEYCLOAK_HOME/data/transaction-logs.

Removed offline session preloading

The old behavior to preload offline sessions at startup is now removed after it has been deprecated in the previous release.

Specify cache options at runtime

Options cache, cache-stack, and cache-config-file are no longer build options, and they can be specified only during runtime. This eliminates the need to execute the build phase and rebuild your image due to them. Be aware that they will not be recognized during the build phase, so you need to remove them.

kcadm and kcreg changes

How kcadm and kcreg parse and handle options and parameters has changed. Error messages from usage errors, the wrong option or parameter, may be slightly different than previous versions. Also usage errors will have an exit code of 2 instead of 1.

Removing custom user attribute indexes

When searching for users by user attribute, Keycloak no longer searches for user attribute names forcing lower case comparisons. This means Keycloak’s native index on the user attribute table will now be used when searching. If you have created your own index based on `lower(name)`to speed up searches, you can now remove it.

New default client scope basic

The new client scope named basic is added as a realm "default" client scope and hence will be added to all newly created OIDC clients. The client scope is also automatically added to all existing OIDC clients during migration.

This scope contains preconfigured protocol mappers for the following claims:

  • sub (See the details below in the dedicated section)

  • auth_time

This provides additional help to reduce the number of claims in a lightweight access token, but also gives the chance to configure claims that were always added automatically.

In case you already have client scope named basic in some of your realms, then the new client scope basic will not be added to your realm and will not be added to any clients. The migration would be ignored for this particular case. In that case, you either need to make sure to rename your client scope to something different than basic before you migrate to this Keycloak version or you need to manually deal with missing sub and auth_time claims in case you need them in your tokens and you may need to manually add corresponding protocol mappers to some of your client scopes.

Removed session_state claim

The session_state claim, which contains the same value as the sid claim, is now removed from all tokens as it is not required according to the OpenID Connect Front-Channel Logout and OpenID Connect Back-Channel Logout specifications. The session_state claim remains present in the Access Token Response in accordance with OpenID Connect Session Management specification.

Note that the setSessionState() method is also removed from the IDToken class in favor of the setSessionId() method, and the getSessionState() method is now deprecated.

A new Session State (session_state) mapper is also included and can be assigned to client scopes (for instance basic client scope) to revert to the old behavior.

If an old version of the JS adapter is used, the Session State (session_state) mapper should also be used by using client scopes as described above.

sub claim is added to access token via protocol mapper

The sub claim, which was always added to the access token, is now added by default but using a new Subject (sub) protocol mapper.

The Subject (sub) mapper is configured by default in the basic client scope. Therefore, no extra configuration is required after upgrading to this version.

If you are using the Pairwise subject identifier mapper to map a sub claim for an access token, you can consider disabling or removing the Subject (sub) mapper, however it is not strictly needed as the Subject (sub) protocol mapper is executed before the Pairwise subject identifier mapper and hence the pairwise value will override the value added by Subject (sub) mapper. This may apply also to other custom protocol mapper implementations, which override the sub claim, as the Subject (sub) mapper is currently executed as first protocol mapper.

You can use the Subject (sub) mapper to configure the sub claim only for access token, lightweight access token, and introspection response. IDToken and Userinfo always contain sub claim.

The mapper has no effects for service accounts, because no user session exists, and the sub claim is always added to the access token.

Nonce claim is only added to the ID token

The nonce claim is now only added to the ID token strictly following the OpenID Connect Core 1.0 specification. As indicated in the specification, the claim is compulsory inside the ID token when the same parameter was sent in the authorization request. The specification also recommends to not add the nonce after a refresh request. Previously, the claim was set to all the tokens (Access, Refresh and ID) in all the responses (refresh included).

A new Nonce backwards compatible mapper is also included in the software that can be assigned to client scopes to revert to the old behavior. For example, the JS adapter checked the returned nonce claim in all the tokens before fixing issue #26651 in version 24.0.0. Therefore, if an old version of the JS adapter is used, the mapper should be added to the required clients by using client scopes.

The userId in the REFRESH_TOKEN event is now always taken from user session instead of sub claim in the refresh token. The userId in the REFRESH_TOKEN_ERROR event is now always null. The reason for this change is that the value of the sub claim in the refresh token may be null with the introduction of the optional sub claim or even different from the real user id when using pairwise subject identifiers or other ways to override the sub claim.

However a refresh_token_sub detail is now added as backwards compatibility to have info about the user in the case of missing userId in the REFRESH_TOKEN_ERROR event.

Using older javascript adapter

If you use the latest Keycloak server with older versions of the javascript adapter in your applications, you may be affected by the token changes mentioned above as previous versions of javascript adapter rely on the claims, which were added by Keycloak, but not supported by the OIDC specification. This includes:

  • Adding the Session State (session_state) mapper in case of using the Keycloak Javascript adapter 24.0.3 or older

  • Adding the Nonce backwards compatible mapper in case of using a Keycloak Javascript adapter that is older than Keycloak 24

You can add the protocol mappers directly to the corresponding client or to some client scope, which can be used by your client applications relying on older versions of the Keycloak Javascript adapter. Some more details are in the previous sections dedicated to session_state and nonce claims.

Default http-pool-max-threads reduced

http-pool-max-threads if left unset will default to the greater of 50 or 4 x (available processors). Previously it defaulted to the greater of 200 or 8 x (available processors). Reducing the number or task threads for most usage scenarios will result in slightly higher performance due to less context switching among active threads.

Management port for metrics and health endpoints

The /health and /metrics endpoints are accessible on the management port 9000, which is turned on by default. That means these endpoints are no longer exposed to the standard Keycloak ports 8080 and 8443.

In order to reflect the old behavior, use the property --legacy-observability-interface=true, which will not expose these endpoints on the management port. However, this property is deprecated and will be removed in future releases, so it is recommended not to use it.

The management interface uses a different HTTP server than the default Keycloak HTTP server, and it is possible to configure them separately. Beware, if no values are supplied for the management interface properties, they are inherited from the default Keycloak HTTP server.

For more details, see Configuring the Management Interface.

Escaping slashes in group paths

Keycloak has never escaped slashes in the group paths. Because of that, a group named group/slash child of top uses the full path /top/group/slash, which is clearly misleading. Starting with this version, the server can be started to perform escaping of those slashes in the name:

bin/kc.[sh|bat] start --spi-group-jpa-escape-slashes-in-group-path=true

The escape char is the tilde character ~. The previous example results in the path /top/group~/slash. The escape marks the last slash is part of the name and not a hierarchy separator.

The escaping is currently disabled by default because it represents a change in behavior. Nevertheless enabling escaping is recommended and it can be the default in future versions.

Change to class EnvironmentDependentProviderFactory

The method EnvironmentDependentProviderFactory.isSupported() was deprecated for several releases and has now been removed.

Instead, implement isSupported(Config.Scope config).

Removal of the deprecated LinkedIn provider

In version 22.0.2 the OAuh 2.0 social provider for LinkedIn was replaced by a new OpenId Connect implementation. The legacy provider was deprecated but not removed, just in case it was still functional in some existing realms. Keycloak 25.0.0 is definitely removing the old provider and its associated linkedin-oauth feature. From now on, the default LinkedIn social provider is the only option available.

Improved performance of findGrantedResources and findGrantedOwnerResources queries

These queries performed poorly when the RESOURCE_SERVER_RESOURCE and RESOURCE_SERVER_PERM_TICKET tables had over 100k entries and users were granted access to over 1k resources. The queries were simplified and new indexes for the requester and owner columns were introduced.

The new indexes are both applied to the RESOURCE_SERVER_PERM_TICKET table. If the table currently contains more than 300.000 entries, Keycloak will skip the creation of the indexes by default during the automatic schema migration, and will instead log the SQL statements on the console during migration. In this case, the statements must be run manually in the DB after Keycloak’s startup.

See the Upgrading Guide for details on how to configure a different limit.

Removing deprecated methods from AccessToken, IDToken, and JsonWebToken classes

The following methods were removed from the AccessToken class:

  • expiration. Use the exp method instead.

  • notBefore. Use the nbf method instead.

  • issuedAt. Use the iat method instead.

The following methods were removed from the IDToken class:

  • getAuthTime and setAuthTime. Use the getAuth_time and setAuth_time methods, respectively.

  • notBefore. Use the nbf method instead.

  • issuedAt. Use the iat method instead.

  • setSessionState. Use the setSessionId method instead (See the details above in the section about session_state claim)

The following methods were removed from the JsonWebToken class:

  • expiration. Use the exp method instead.

  • notBefore. Use the nbf method instead.

  • issuedAt. Use the iat method instead.

You should also expect both exp and nbf claims not set in tokens as they are optional. Previously, these claims were being set with a value of 0 what does not make mush sense because their value should be a valid NumericDate.

Method getExp added to SingleUseObjectKeyModel

As a consequence of the removal of deprecated methods from AccessToken, IDToken, and JsonWebToken, the SingleUseObjectKeyModel also changed to keep consistency with the method names related to expiration values.

The previous getExpiration method is now deprecated and you should prefer using new newly introduced getExp method to avoid overflow after 2038.

Method encode deprecated on PasswordHashProvider

Method String encode(String rawPassword, int iterations) on the interface org.keycloak.credential.hash.PasswordHashProvider is deprecated. The method will be removed in one of the future Keycloak releases. It might be Keycloak 27 release.

CollectionUtil intesection method removed

The method org.keycloak.common.util.CollectionUtil.intersection has been removed. You should use the 'java.util.Collection.retainAll' instead on an existing collection.

Resteasy util class is deprecated

org.keycloak.common.util.Resteasy has been deprecated. You should use the org.keycloak.util.KeycloakSessionUtil to obtain the KeycloakSession instead.

It is highly recommended to avoid obtaining the KeycloakSession by means other than when creating your custom provider.

Small changes in session lifespan and idle calculations

In previous versions the session max lifespan and idle timeout calculation was slightly different when validating if a session was still valid. Since now that validation uses the same code than the rest of the project.

If the session is using the remember me feature, the idle timeout and max lifespan are the maximum value between the common SSO and the remember me configuration values.

External Infinispan requirements

Keycloak now requires a Infinispan server version of at least 15.0.0 for external Infinispan deployments. An external Infinispan deployment is supported for multi-site setups as outlined in the HA guide.

Oracle Database driver not part of the distribution

The Oracle Database JDBC driver is no longer part of the Keycloak distribution. If you wish to use Oracle DB, you must manually install a version of the Oracle Driver that is compatible with your specific environment. Instructions for this process can be found in the Configuring the database guide.

Deprecated theme variables

The following variables were deprecated in the Admin theme and will be removed in a future version:

  • authServerUrl. Use serverBaseUrl instead.

  • authUrl. Use adminBaseUrl instead.

The following variables were deprecated in the Account theme and will be removed in a future version:

  • authServerUrl. Use serverBaseUrl instead, note serverBaseUrl does not include trailing slash.

  • authUrl. Use serverBaseUrl instead, note serverBaseUrl does not include trailing slash.

Methods to get and set current refresh token in client session are now deprecated

The methods String getCurrentRefreshToken(), void setCurrentRefreshToken(String currentRefreshToken), int getCurrentRefreshTokenUseCount(), and void setCurrentRefreshTokenUseCount(int currentRefreshTokenUseCount) in the interface org.keycloak.models.AuthenticatedClientSessionModel are deprecated. They have been replaced by similar methods that require an identifier as a parameter such as getRefreshToken(String reuseId) to manage multiple refresh tokens within a client session. The methods will be removed in one of the future Keycloak releases. It might be Keycloak 27 release.

Migrating to 24.0.4

Partial update to user attributes when updating users through the Admin User API is no longer supported

When updating user attributes through the Admin User API, you cannot execute partial updates when updating the user attributes, including the root attributes like username, email, firstName, and lastName.

If you are updating user attributes through the Admin User API without passing all the attributes that the administrator has write permissions, the missing attributes will be removed. On the other hand, if an attribute is marked as read-only for administrators, not sending the attribute won’t remove it.

See the User Profile Documentation for the details about the user profile settings.

Migrating to 24.0.3

Changes to the org.keycloak.userprofile.UserProfileDecorator interface

To properly support multiple user storage providers within a realm, the org.keycloak.userprofile.UserProfileDecorator interface has changed.

The decorateUserProfile method is no longer invoked when parsing the user profile configuration for the first time (and caching it), but every time a user is being managed through the user profile provider. As a result, the method changed its contract to:

List<AttributeMetadata> decorateUserProfile(String providerId, UserProfileMetadata metadata)

Differently than the previous contract and behavior, this method is only invoked for the user storage provider from where the user was loaded from.

Changes in redirect URI verification when using wildcards

Because of security concerns, the redirect URI verification now performs a exact string matching (no wildcard involved) if the passed redirect uri contains a userinfo part or its path accesses parent directory (/../).

The full wildcard * can still be used as a valid redirect in development for http(s) URIs with those characteristics. In production environments a exact valid redirect URI without wildcard needs to be configured for any URI of that type.

Please note that wildcard valid redirect URIs are not recommended for production and not covered by the OAuth 2.0 specification.

Deprecated Account REST endpoint for removing credential

The Account REST endpoint for removing the credential of the user is deprecated. Starting at this version, the Account Console no longer uses this endpoint. It is replaced by the Delete Credential application-initiated action, which is triggered by the Account Console when a user want to remove the credential of a user.

Migrating to 24.0.2

Changes to Password Hashing

The release notes for Keycloak 24.0.0 have been updated with corrected description of the expected performance impact for the change, as well as sizing guide.

Migrating to 24.0.0

Changes to the Welcome theme

The 'welcome' theme has has been updated to use a new layout and now uses PatternFly 5, rather than PatternFly 3. If you are extending the theme, or providing your own, you may need to update it as follows:

Migrate from PatternFly 3 to PatternFly 5

The welcome theme was one of the more outdated themes in Keycloak. It was originally based on PatternFly 3, but has now been updated to use PatternFly 5, skipping a major version in the process. If your custom theme extends the built-in theme, you will need to update it to use PatternFly 5 syntax. Consult the PatternFly 5 documentation for details.

If you are still using PatternFly 3 in your own custom theme (not extending the built-in one), you can continue to use it, but PatternFly 3 support will be removed in a future release, so you should consider migrating to PatternFly 5 as soon as possible.

Automatic redirect to the Admin Console

If the Admin Console is enabled, the welcome page will automatically redirect to it if the administrative user already exists. This behavior can be modified by setting the redirectToAdmin in your theme.properties file. By default, the property is set to false, unless you are extending the built-in theme, in which case, the property is set to true.

These properties were previously used for navigational elements that are now no longer present. If you are extending the built-in theme, you will need to remove these properties from your theme.properties file, as they no longer have any effect.

Assets are now loaded from 'common' resources

Images such as the background, logo and favicon are now loaded from the 'common' resources, rather than the theme resources. This change means that if you are extending the built-in theme, and are overwriting these images, you will need to move them to the 'common' resources of your theme, and update your theme.properties file to include the new paths:

# This defaults to 'common/keycloak' if not set.
import=common/your-theme-name

Changes to the Account Console theme customization

If you were previously extending the now deprecated version 2 of the Account Console theme, you will need to update your theme to use the new version 3 of the Account Console theme. The new version of the Account Console theme comes with some changes in regards to how it is customized. To start with a clean slate, you can follow the new customization quickstart.

To move your custom theme start by changing the parent to the new theme:

# Before
parent=keycloak.v2

# After
parent=keycloak.v3

If you have any custom React components, you will import React directly, rather than using a relative path:

// Before
import * as React from "../../../../common/keycloak/web_modules/react.js";

// After
import React from "react";

If you are using content.json to customize the theme there are some changes to the structure of the file, specifically:

  • The content property has been renamed to children.

  • The id, icon and componentName properties have been removed, as modulePath provides the same functionality.

Keycloak JS imports might need to be updated

If you are loading Keycloak JS directly from the Keycloak server, this section can be safely ignored. If you are loading Keycloak JS from the NPM package and are using a bundler like Webpack, Vite, and so on, you might need to make some changes to your code. The Keycloak JS package now uses the exports field in the package.json file. This means that you might have to change your imports:

// Before
import Keycloak from 'keycloak-js/dist/keycloak.js';
import AuthZ from 'keycloak-js/dist/keycloak-authz.js';

// After
import Keycloak from 'keycloak-js';
import AuthZ from 'keycloak-js/authz';

Features Changes

It is no longer allowed to have the same feature in both the --features and --features-disabled list. The feature should appear in only one list.

The usage of unversioned feature names, such as docker, in the --features list will allow for the most supported / latest feature version to be enabled for you. If you need more predictable behavior across releases, reference the particular version you want instead, such as docker:v1.

User Profile Changes

User profile enabled by default

The user profile feature is now enabled by default. The `declarative-user-profile`feature is no longer available, because the user profile is assumed to be enabled. Therefore, the User Profile Enabled switch is removed from the Realm Settings and replaced by Unmanaged attributes. When migrating from previous version, the behavior is as follows:

  • For the deployments where User Profile Enabled was set to ON, Unmanaged attributes will be set to OFF after the upgrade. As a result, only user attributes supported explicitly by user profile will be allowed.

  • For the deployments where the User Profile Enabled was set to OFF (which was also the default settings for the deployments with declarative-user-profile feature disabled, which was the default), Unmanaged attributes will be set to ON` after the upgrade. As a result, the behavior should be basically the same as in previous versions with the user profile disabled. The Attributes tab will remain in the user details part of the Admin Console. Also users can now set arbitrary attributes through UI pages such as the registration page and update profile page as long as a particular custom theme supports it. The custom themes should work as before as well. However, consider updating your themes to use the user-profile and maybe even remove your custom themes if those themes were need to add custom attributes. See the subsequent section on themes. Also, consider toggling Unmanaged attributes to OFF or enable this switch only for administrators so that you can rely on mainly on using managed attributes.

See the User Profile Documentation for the details about the Unmanaged attributes.

Default validations

Default user profile configuration comes with a set of default validations for the basic predefined fields. Those validations were not present in previous versions when the declarative-user-profile feature was disabled by default. If you have issues due to backward compatibility, you can change the default validators according to your needs. The default validators are as follows:

  • The`username`, email, firstName and lastName attributes have a maximum length of 255 characters. These validations were indirectly present in previous versions as well because of the database constraint on the table USER_ENTITY for those fields with a maximum length of 255 characters. However, when using user storage providers, it might be possible before to use longer values.

  • The username attribute has a minimum length of three characters. Username has also username-prohibited-characters and up-username-not-idn-homograph validator by default, which were not present in previous versions. See the Validation section of the User Profile Documentation for the details about those attributes. Note that username is not editable by default unless you have the realm switch Edit username enabled. This change means that existing users with incorrect usernames should still work and they will not be enforced to update their usernames. But new users will be enforced to use correct usernames during their registration or creation by the admin REST API.

  • The firstName and lastName attributes have the person-name-prohibited-characters validator on them, which were not present in previous versions. See the Validation section of the User Profile Documentation for the details about those attributes. Note that both first name and last name are editable by default, so users, who already have such incorrect first/last name from a previous version will be forced to update them when updating their user profiles.

User attribute names with strange characters

In previous versions, you could create a user with attribute names such as some:attribute or some/attribute. The user profile intentionally does not allow you to create attributes with such strange names in the user profile configuration. So you may need to configure Unmanaged attributes for your realm and enable unmanaged attributes for administrators (ideally) or for end users (if really needed). Although it is strongly preferred to avoid using such attribute names.

Verify Profile required action enabled by default

The verify-profile required action is enabled by default for new realms. However, when you migrate from a previous version, your existing realms will have the same state of this verify-profile action as before, which usually means disabled as it was disabled by default in previous versions. For the details about this required action, see the User Profile Documentation.

Breaking changes to the User Profile SPI

If you are using the User Profile SPI in your extension, you might be impacted by the API changes introduced in this release.

The org.keycloak.userprofile.Attributes interface includes the following changes:

  • Method getValues was renamed to get to make it more aligned with the same operation from a regular Java Map

  • Method isRootAttribute was moved to the utility class org.keycloak.userprofile.UserProfileUtil.isRootAttribute

  • Method getFirstValue was renamed to getFirst to make it less verbose

  • Method getReadable(boolean) was removed and now all attributes (including root attributes) are returned whenever they have read rights.

Changes to Freemarker templates to render pages based on the user profile and realm

In this release, the following templates were updated to make it possible to dynamically render attributes based on the user profile configuration set to a realm:

  • login-update-profile.ftl

  • register.ftl

  • update-email.ftl

These templates are responsible for rendering the update profile (when the Update Profile required action is enabled for a user), the registration, and the update email (when the UPDATE_EMAIL feature is enabled) pages, respectively.

If you use a custom theme to change these templates, they will function as expected because only the content is updated. However, we recommend you to take a look at how to configure a {declarative user profile} and possibly avoid changing the built-in templates by using all the capabilities provided by this feature.

Also, the templates used by the declarative-user-profile feature to render the pages for the same flows are longer necessary and removed in this release:

  • update-user-profile.ftl

  • register-user-profile.ftl

If you were using the declarative-user-profile feature in a previous release with customizations to the above templates, update the login-update-profile.ftl and register.ftl accordingly.

New Freemarker template for the update profile page at first login through a broker

In this release, the server will render the update profile page when the user is authenticating through a broker for the first time using the idp-review-user-profile.ftl template.

In previous releases, the template used to update the profile during the first broker login flow was the login-update-profile.ftl, the same used to update the profile when users are authenticating to a realm.

By using separate templates for each flow, a more clear distinction exist as to which flow a template is actually used rather than sharing a same template, and potentially introduce unexpected changes and behavior that should only affect pages for a specific flow.

If you have customizations to the login-update-profile.ftl template to customize how users update their profiles when authenticating through a broker, make sure to move your changes to the new template.

Truststore Changes

The spi-truststore-file-* options and the truststore related options https-trust-store-* are deprecated. Therefore, use the new default location for truststore material, conf/truststores, or specify your desired paths by using the truststore-paths option. For details, see the relevant guide.

The tls-hostname-verifier property should be used instead of the spi-truststore-file-hostname-verification-policy property.

A collateral effect of the changes is that now the truststore provider is always configured with some certificates (at least the default java trusted certificates are present). This new behavior can affect other parts of Keycloak.

For example, webauthn registration can fail if attestation conveyance was configured to Direct validation. Previously, if the truststore provider was not configured the incoming certificate was not validated. But now this validation is always performed. The registration fails with invalid cert path error as the certificate chain sent by the dongle is not trusted by Keycloak. The Certificate Authorities of the authenticator need to be present in the truststore provider to correctly perform the attestation.

Deprecated --proxy option

The --proxy option has been deprecated and will be removed in a future release. The following table explains how the deprecated option maps to supported options.

Deprecated usage New usage

kc.sh (no proxy option set)

kc.sh

kc.sh --proxy none

kc.sh

kc.sh --proxy edge

kc.sh --proxy-headers forwarded|xforwarded --http-enabled true

kc.sh --proxy passthrough

kc.sh --hostname-port 80|443 (depending if HTTPS is used)

kc.sh --proxy reencrypt

kc.sh --proxy-headers forwarded|xforwarded

For hardened security, the --proxy-headers option does not allow selecting both forwarded and xforwarded values at the same time (as it was the case before for --proxy edge and --proxy reencrypt).
When using the proxy headers option, make sure your reverse proxy properly sets and overwrites the Forwarded or X-Forwarded-* headers respectively. To set these headers, consult the documentation for your reverse proxy. Misconfiguration will leave Keycloak exposed to security vulnerabilities.

You can also set the proxy headers when using the Operator:

apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
  name: example-kc
spec:
  ...
  proxy:
    headers: forwarded|xforwarded
If the proxy.headers field is not specified, the Operator falls back to the previous behavior by implicitly setting proxy=passthrough by default. This results in deprecation warnings in the server log. This fallback will be removed in a future release.

Changes to the user representation in both Admin API and Account contexts

Both org.keycloak.representations.idm.UserRepresentation and org.keycloak.representations.account.UserRepresentation representation classes have changed so that the root user attributes (such as username, email, firstName, lastName, and locale) have a consistent representation when fetching or sending the representation payload to the Admin and Account APIS, respectively.

The username, email, firstName, lastName, and locale attributes were moved to a new org.keycloak.representations.idm.AbstractUserRepresentation base class.

Also the getAttributes method is targeted for representing only custom attributes, so you should not expect any root attribute in the map returned by this method. This method is mainly targeted for clients when updating or fetching any custom attribute for a give user.

In order to resolve all the attributes including the root attributes, a new getRawAttributes method was added so that the resulting map also includes the root attributes. However, this method is not available from the representation payload and it is targeted to be used by the server when managing user profiles.

https-client-auth is a build time option

Option https-client-auth had been treated as a run time option, however this is not supported by Quarkus. The option needs to be handled at build time instead.

Sequential loading of offline sessions and remote sessions

Starting with this release, the first member of a Keycloak cluster will load remote sessions sequentially instead of in parallel. If offline session preloading is enabled, those will be loaded sequentially as well.

The previous code led to high resource-consumption across the cluster at startup and was challenging to analyze in production environments and could lead to complex failure scenarios if a node was restarted during loading. Therefore, it was changed to sequential session loading.

For offline sessions, the default in this and previous versions of Keycloak is to load those sessions on demand, which scales better with a lot of offline sessions than the attempt to preload them in parallel. Setups that use this default setup are not affected by the change of the loading strategy for offline sessions. Setups that have offline session preloading enabled should migrate to a setup where offline-session preloading is disabled.

Deprecated offline session preloading

The default behavior of Keycloak is to load offline sessions on demand. The old behavior to preload them at startup is now deprecated, as preloading them at startup does not scale well with a growing number of sessions, and increases Keycloak memory usage. The old behavior will be removed in a future release.

To re-enable old behavior while it is deprecated and not removed yet, use the feature flag and the SPI option as shown below:

bin/kc.[sh|bat] start --features-enabled offline-session-preloading --spi-user-sessions-infinispan-preload-offline-sessions-from-database=true

The API of UserSessionProvider deprecated the method getOfflineUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId). Instead of this method, use getOfflineUserSessionByBrokerUserIdStream(RealmModel, String brokerUserId) to first get the sessions of a user, and then filter by the broker session ID as needed.

Infinispan metrics use labels for cache manager and cache names

When enabling metrics for Keycloak’s embedded caches, the metrics now use labels for the cache manager and the cache names.

Old metric example without labels
vendor_cache_manager_keycloak_cache_sessions_statistics_approximate_entries_in_memory{cache="sessions",node="..."}
New metric example with labels
vendor_statistics_approximate_entries_in_memory{cache="sessions",cache_manager="keycloak",node="..."}

To revert the change for an installation, use a custom Infinispan XML configuration and change the configuration as follows:

<metrics names-as-tags="false" />

User attribute value length extension

As of this release, Keycloak supports storing and searching by user attribute values longer than 255 characters, which was previously a limitation.

In setups where users are allowed to update attributes, for example, via the account console, prevent denial of service attacks by adding validations. Ensure that no unmanaged attributes are allowed and all editable attributes have a validation that limits the input length.

For unmanaged attributes, the maximum length is 2048 characters. For managed attributes, the default maximum length is 2048 characters. Administrator can change this by adding a validator of type length.

Keycloak caches user-related objects in its internal caches. Using longer attributes increases the memory that is consumed by the cache. Therefore, limiting the size of the length attributes is recommended. Consider storing large objects outside Keycloak and reference them by ID or URL.

This change adds new indexes on the tables USER_ATTRIBUTE and FED_USER_ATTRIBUTE. If those tables contain more than 300000 entries, Keycloak will skip the index creation by default during the automatic schema migration and instead log the SQL statement on the console during migration to be applied manually after Keycloak’s startup. See the Upgrading Guide for details on how to configure a different limit.

The newly added indexes USER_ATTR_LONG_VALUES_LOWER_CASE and FED_USER_ATTR_LONG_VALUES_LOWER_CASE may exceed the maximum limit of 30 characters set by Oracle, in case the database is running in compatibility mode. Since Oracle version 12.2, there is a support for longer index names.
Additional migration steps for LDAP

This is for installations that match all the following criteria:

  • User attributes in the LDAP directory are larger than 2048 characters or binary attributes that are larger than 1500 bytes.

  • The attributes are changed by admins or users via the admin console, the APIs or the account console.

To be able to enable changing those attributes via UI and REST APIs, perform the following steps:

  1. Declare the attributes identified above as managed attributes in the user profile of the realm.

  2. Define a length validator for each attribute added in the previous step specifying the desired minimum and maximum length of the attribute value. For binary values, add 33 percent to the expected binary length to count in the overhead for Keycloak’s internal base64 encoding of binary values.

Additional migration steps for custom user storage providers

This is for installations that match all the following criteria:

  • Running MariaDB or MySQL as a database for Keycloak.

  • Entries in table FED_USER_ATTRIBUTE with contents in the VALUE column that are larger than 2048 characters. This table is used for custom user providers which have federation enabled.

  • The long attributes are changed by admins or users via the admin console or the account console.

To be able to enable changing those attributes via UI and REST APIs, perform the following steps:

  1. Declare the attributes identified above as managed attributes in the user profile of the realm.

  2. Define a length validator for each attribute added in the previous step specifying the desired minimum and maximum length of the attribute value.

The Admin send-verify-email API now uses the same email verification template

PUT /admin/realms/{realm}/users/{id}/send-verify-email

In this release, the API will use the email-verification.ftl template instead of executeActions.ftl.

Before upgrading
Perform the following action(s): Verify Email
After upgrading
Confirm validity of e-mail address email@example.org.

If you have customized the executeActions.ftl template to modify how users verify their email using this API, ensure that you transfer your modifications to the new template.

A new parameter called lifespan will be introduced to allow overriding of the default lifespan value (12 hours).

If you prefer the previous behavior, use the execute-actions-email API as follows.

PUT /admin/realms/{realm}/users/{id}/execute-actions-email

["VERIFY_EMAIL"]

Removal of the deprecated mode for SAML encryption

The compatibility mode for SAML encryption introduced in version 21 is now removed. The system property keycloak.saml.deprecated.encryption is not managed anymore by the server. The clients which still used the old signing key for encryption should update it from the new IDP configuration metadata.

Changes to Password Hashing

In this release, we adapted the password hashing defaults to match the OWASP recommendations for Password Storage.

As part of this change, the default password hashing provider has changed from pbkdf2-sha256 to pbkdf2-sha512. Also, the number of default hash iterations for pbkdf2 based password hashing algorithms changed as follows:

Provider ID Algorithm Old Iterations New Iterations

pbkdf2

PBKDF2WithHmacSHA1

20.000

1.300.000

pbkdf2-sha256

PBKDF2WithHmacSHA256

27.500

600.000

pbkdf2-sha512

PBKDF2WithHmacSHA512

30.000

210.000

If a realm does not explicitly configure a password policy with hashAlgorithm and hashIterations, then the new configuration will take effect on the next password based login, or when a user password is created or updated.

Performance of new password hashing configuration

Tests on a machine with an Intel i9-8950HK CPU (12) @ 4.800GHz yielded the following ⌀ time differences for hashing 1000 passwords (averages from 3 runs). Note that the average duration for the PBKDF2WithHmacSHA1 was computed with a lower number of passwords due to the long runtime.

Provider ID Algorithm Old duration New duration Difference

pbkdf2

PBKDF2WithHmacSHA1

122ms

3.114ms

+2.992ms

pbkdf2-sha256

PBKDF2WithHmacSHA256

20ms

451ms

+431ms

pbkdf2-sha512

PBKDF2WithHmacSHA512

33ms

224ms

+191ms

Users of the pbkdf2 provider might need to explicitly reduce the number of hash iterations to regain acceptable performance. This can be done by configuring the hash iterations explicitly in the password policy of the realm.

Expected increased overall CPU usage and temporary increased database activity

The Concepts for sizing CPU and memory resources in the Keycloak High Availability guide have been updated to reflect the new hashing defaults. The CPU usage per password-based login in our tests increased by the factor of five, which includes both the changed password hashing and unchanged TLS connection handling. The overall CPU increase should be around the factor of two to three due to the averaging effect of Keycloak’s other activities like refreshing access tokens and client credential grants. Still, this depends on the unique workload of an installation.

After the upgrade, during a password-based login, the user’s passwords will be re-hashed with the new hash algorithm and hash iterations as a one-off activity and updated in the database. As this clears the user from Keycloak’s internal cache, you will also see an increased read activity on the database level. This increased database activity will decrease over time as more and more user’s passwords have been re-hashed.

How to keep using the old pbkdf2-sha256 password hashing?

To keep the old password hashing for a realm, specify hashAlgorithm and hashIterations explicitly in the realm password policy.

  • Hashing Algorithm: pbkdf2-sha256

  • Hashing Iterations: 27500

Operator Referenced Resource Polling

Secrets and ConfigMaps referenced via the Keycloak CR will now be polled for changes, rather than watched via the api server. It may take around 1 minute for changes to be detected.

This was done so to not require label manipulation on those resources. After upgrading if any Secret still has the operator.keycloak.org/component label, it may be removed or ignored.

Renaming JPA provider configuration options for migration

After removal of the Map Store the following configuration options were renamed:

  • spi-connections-jpa-legacy-initialize-empty to spi-connections-jpa-quarkus-initialize-empty

  • spi-connections-jpa-legacy-migration-export to spi-connections-jpa-quarkus-migration-export

  • spi-connections-jpa-legacy-migration-strategy to spi-connections-jpa-quarkus-migration-strategy

Renaming model modules

After removal of the Map Store the following modules were renamed:

  • org.keycloak:keycloak-model-legacy-private to org.keycloak:keycloak-model-storage-private

  • org.keycloak:keycloak-model-legacy-services to org.keycloak:keycloak-model-storage-services

and org.keycloak:keycloak-model-legacy module was deprecated and will be removed in the next release in favour of org.keycloak:keycloak-model-storage module.

Temporary lockout log replaced with event

There is now a new event USER_DISABLED_BY_TEMPORARY_LOCKOUT when a user is temporarily locked out by the brute force protector. The log with ID KC-SERVICES0053 has been removed as the new event offers the information in a structured form.

As it is a success event, the new event is logged by default at the DEBUG level. Use the setting spi-events-listener-jboss-logging-success-level as described in the Event listener chapter in the Server Administration Guide to change the log level of all success events.

To trigger custom actions or custom log entries, write a custom event listener as described in the Event Listener SPI in the Server Developer Guide.

Operator Customization Property Keys

The property keys used by the operator for advanced configuration have changed from operator.keycloak to kc.operator.keycloak.

Keycloak CR resources options

When no resources options are specified in the Keycloak CR and KeycloakRealmImport CR, default values are used. The default requests memory for Keycloak deployment and the realm import Job is set to 1700MiB, and the limits memory is set to 2GiB.

Updates to cookies

As part of refactoring cookie handling in Keycloak there are some changes to how cookies are set:

  • All cookies will now have the secure attribute set if the request is through a secure context

  • WELCOME_STATE_CHECKER cookies now set SameSite=Strict

For custom extensions there may be some changes needed:

  • LocaleSelectorProvider.KEYCLOAK_LOCALE is deprecated as cookies are now managed through the CookieProvider

  • HttpResponse.setWriteCookiesOnTransactionComplete has been removed

  • HttpCookie is deprecated, please use NewCookie.Builder instead

  • ServerCookie is deprecated, please use NewCookie.Builder instead

Internal algorithm changed from HS256 to HS512

The algorithm that Keycloak uses to sign internal tokens (a JWT which is consumed by Keycloak itself, for example a refresh or action token) is being changed from HS256 to the more secure HS512. A new key provider named hmac-generated-hs512 is now added for realms. Note that in migrated realms the old hmac-generated provider and the old HS256 key are maintained and still validate tokens issued before the upgrade. The HS256 provider can be manually deleted when no more old tokens exist following the rotating keys guidelines.

Different JVM memory settings when running in a container

The JVM options -Xms and -Xmx were replaced by -XX:InitialRAMPercentage and -XX:MaxRAMPercentage when running in a container. Instead of the static maximum heap size settings, Keycloak specifies the maximum as 70% of the total container memory.

As the heap size is dynamically calculated based on the total container memory, you should always set the memory limit for the container.

If the memory limit is not set, the memory consumption rapidly increases as the maximum heap size grows up to 70% of the total container memory.

For more details, see the Running Keycloak in a container guide.

GELF log handler has been deprecated

With sunsetting of the underlying library providing integration with GELF, Keycloak will no longer support the GELF log handler out-of-the-box. This feature will be removed in a future release. If you require an external log management, consider using file log parsing.

Migrating to 23.0.5

Changes in jboss-logging event messages

Because of issue #25078, the jboss-logging message values are now quoted (character " by default) and sanitized to prevent any line break. There are two new options in the provider (spi-events-listener-jboss-logging-sanitize and spi-events-listener-jboss-logging-quotes) that allow you to customize the new behavior. For example, to avoid both sanitization and quoting, the server can be started in this manner:

./kc.sh start --spi-events-listener-jboss-logging-sanitize=false --spi-events-listener-jboss-logging-quotes=none ...

For more information about the options, see all provider configuration guide.

Migrating to 23.0.4

Fix handling of Groups.getSubGroups briefRepresentation parameter

Version 23.0.0 introduced a new endpoint getSubGroups ("children") on the Groups resource, where the meaning of the parameter briefRepresentation meant the retrieval of full representations of the sub groups. The meaning is now changed to return the brief representation.

Migrating to 23.0.2

Valid redirect URIs for clients are always compared with exact string matching

Version 1.8.0 introduced a lower-case for the hostname and scheme when comparing a redirect URI with the specified valid redirects for a client. Unfortunately it did not fully work in all the protocols, and, for example, the host was lower-cased for http but not for https. As OAuth 2.0 Security Best Current Practice advises to compare URIs using exact string matching, Keycloak will follow the recommendation and for now on valid redirects are compared with exact case even for the hostname and scheme.

For realms relying on the old behavior, the valid redirect URIs for their clients should now hold separate entries for each URI that should be recognized by the server.

Although it introduces more steps and verbosity when configuring clients, the new behavior enables more secure deployments as pattern-based checks are frequently the cause of security issues. These issues are due to how they are implemented and how they are configured.

Operator -secrets-store Secret

Older versions of the operator created a Secret to track watched Secrets. Newer versions of the operator no longer use the -secrets-store Secret, so it may be deleted.

If you are on 23.0.0 or 23.0.1 and see "org.keycloak.operator.controllers.KeycloakAdminSecretDependentResource → java.lang.IllegalStateException: More than 1 secondary resource related to primary" in the operator log then either delete the -secrets-store Secret, or upgrade to 23.0.2 where this is no longer an issue.

Migrating to 23.0.0

Added iss parameter to OAuth 2.0/OpenID Connect Authentication Response

RFC 9207 OAuth 2.0 Authorization Server Issuer Identification specification adds the parameter iss in the OAuth 2.0/OpenID Connect Authentication Response for realizing secure authorization responses.

In past releases, we did not have this parameter, but now Keycloak adds this parameter by default, as required by the specification.

However, some OpenID Connect / OAuth2 adapters, and especially older Keycloak adapters, may have issues with this new parameter.

For example, the parameter will be always present in the browser URL after successful authentication to the client application. In these cases, it may be useful to disable adding the iss parameter to the authentication response. This can be done for the particular client in the Keycloak Admin Console, in client details in the section with OpenID Connect Compatibility Modes, described in Compatibility with older adapters. Dedicated Exclude Issuer From Authentication Response switch exists, which can be turned on to prevent adding the iss parameter to the authentication response.

Wildcard characters handling

JPA allows wildcards % and _ when searching, while other providers like LDAP allow only *. As * is a natural wildcard character in LDAP, it works in all places, while with JPA it only worked at the beginning and the end of the search string. Starting with this release the only wildcard character is * which work consistently across all providers in all places in the search string. All special characters in a specific provider like % and _ for JPA are escaped. For exact search, with added quotes such as "w*ord", the behavior remains the same as in previous releases.

Language files for themes default to UTF-8 encoding

This release now follows the standard mechanisms of Java and later, which assumes resource bundle files to be encoded in UTF-8.

Previous versions of Keycloak supported specifying the encoding in the first line with a comment like # encoding: UTF-8, which is no longer supported and is ignored.

Message properties files for themes are now read in UTF-8 encoding, with an automatic fallback to ISO-8859-1 encoding. If you are using a different encoding, convert the files to UTF-8.

Changes to the value format of claims mapped by the realm and client role mappers

Before this release, both realm (User Realm Role) and client (User Client Role) protocol mappers were mapping a stringfied JSON array when the Multivalued setting was disabled.

However, the Multivalued setting indicates whether the claim should be mapped as a list or, if disabled, only a single value from the same list of values.

In this release, the role and client mappers now map to a single value from the effective roles of a user when they are marked as single-valued (Multivalued disabled).

Changes to password fields in Login UI

In this version we want to introduce a toggle to hide/show password inputs.

Affected pages:
  • login.ftl

  • login-password.ftl

  • login-update-password.ftl

  • register.ftl

  • register-user-profile.ftl

In general all <input type="password" name="password" /> are encapsulated within a div now. The input element is followed by a button which toggles the visibility of the password input.

Old code example:

<input type="password" id="password" name="password" autocomplete="current-password" style="display:none;"/>

New code example:

<div class="${properties.kcInputGroup!}">
    <input type="password" id="password" name="password" autocomplete="current-password" style="display:none;"/>
    <button class="pf-c-button pf-m-control" type="button" aria-label="${msg('showPassword')}"
            aria-controls="password" data-password-toggle
            data-label-show="${msg('showPassword')}" data-label-hide="${msg('hidePassword')}">
        <i class="fa fa-eye" aria-hidden="true"></i>
    </button>
</div>

Default Keycloak CR Hostname

When running on OpenShift, with ingress enabled, and with the spec.ingress.classname set to openshift-default, you may leave the spec.hostname.hostname unpopulated in the Keycloak CR. The operator will assign a default hostname to the stored version of the CR similar to what would be created by an OpenShift Route without an explicit host - that is ingress-namespace.appsDomain If the appsDomain changes, or should you need a different hostname for any reason, then update the Keycloak CR.

The deprecated auto-build CLI option was removed

The auto-build CLI option has been marked as deprecated for a long time. In this release, it was completely removed, and it is no longer supported.

When executing the start command, the server is automatically built based on the configuration. In order to prevent this behavior, set the --optimized flag.

kc.sh and shell metacharacters

The kc.sh no longer uses an additional shell eval on parameters and the environment variables JAVA_OPTS_APPEND and JAVA_ADD_OPENS, thus the continued use of double escaping/quoting will result in the parameter being misunderstood. For example instead of

bin/kc.sh start --db postgres --db-username keycloak --db-url "\"jdbc:postgresql://localhost:5432/keycloak?ssl=false&connectTimeout=30\"" --db-password keycloak --hostname localhost

Use a single escape:

bin/kc.sh start --db postgres --db-username keycloak --db-url "jdbc:postgresql://localhost:5432/keycloak?ssl=false&connectTimeout=30" --db-password keycloak --hostname localhost

This change also means you cannot invoke kc.sh using a single quoted value of all arguments. For example you can no longer use

bin/kc.sh "start --help"

it must instead be individual arguments

bin/kc.sh start --help

Similarly instead of

bin/kc.sh build "--db postgres"

it must instead be individual arguments

bin/kc.sh build --db postgres

The usage of individual arguments is also required in Dockerfile run commands.

Removed RegistrationProfile form action

The form action RegistrationProfile (displayed in the UI of authentication flows as Profile Validation) was removed from the codebase and also from all authentication flows. By default, it was in the built-in registration flow of every realm. The validation of user attributes as well as creation of the user including all that user’s attributes is handled by RegistrationUserCreation form action and hence RegistrationProfile is not needed anymore. There is usually no further action needed in relation to this change, unless you used RegistrationProfile class in your own providers.

Deprecated methods from data providers and models

  • RealmModel#getTopLevelGroupsStream() and overloaded methods are now deprecated

GroupProvider changes

A new method has been added to allow for searching and paging through top level groups. If you implement this interface you will need to implement the following method:

Stream<GroupModel> getTopLevelGroupsStream(RealmModel realm,
                                           String search,
                                           Boolean exact,
                                           Integer firstResult,
                                           Integer maxResults)

GroupRepresentation changes

  • new field subGroupCount added to inform client how many subgroups are on any given group

  • subGroups list is now only populated on queries that request hierarchy data

  • This field is populated from the "bottom up" so cannot be relied on for getting all subgroups for a group. Use a GroupProvider or request the subgroups from GET {keycloak server}/realms/{realm}/groups/{group_id}/children

New endpoint for Group Admin API

Endpoint GET {keycloak server}/realms/{realm}/groups/{group_id}/children added as a way to get subgroups of specific groups that support pagination

RESTEeasy Reactive

Relying on RESTEasy Classic is not longer an option because it is not available anymore. Migration will be needed for SPI’s and code that is relying on RESTEasy Classic and related packages part of org.jboss.resteasy.spi.*.

Partial export requires manage-realm permission

The endpoint POST {keycloak server}/realms/{realm}/partial-export and the corresponding action in the admin console now require manage-realm permission for execution instead of view-realm. This endpoint exports the realm configuration into a JSON file and the new permission is more appropriate. The parameters exportGroupsAndRoles and exportClients, which include the realm groups/roles and clients in the export respectively, continue managing the same permissions (query-groups and view-clients).

Removal of the options to trim the event’s details length

Since this release, Keycloak supports long value for EventEntity details column. Therefore, it no longer supports options for trimming event detail length --spi-events-store-jpa-max-detail-length and --spi-events-store-jpa-max-field-length.

User Profile updates

This release includes many fixes and updates that are related to user profile as we are working on promoting this feature from preview to officially supported. Minor changes exist for the SPI such as the newly added method boolean isEnabled(RealmModel realm) on UserProfileProvider interface. Also some user profile classes and some validator related classes (but not builtin validator implementations) were moved from keycloak-server-spi-private to keycloak-server-spi module. However, the packages for java classes remain the same. You might be affected in some corner cases, such as when you are overriding the built-in implementation with your own UserProfileProvider implementation. However, note that UserProfileProvider is an unsupported SPI.

Removal of the Map Store

The Map Store has been an experimental feature in previous releases. Starting with this release, it is removed and users should continue to use the current JPA store.

Since this release, it is no longer possible to use --storage related CLI options. The modules keycloak-model-map* have been removed.

Removed namespaces from our translations

All translations are moved into one file for the Admin Console. If you have made your own translations or extended the Admin Console you will need to migrate them to this new format. Also if you have "overrides" in your database, you will have to remove the namespace from the keys. Some keys are the same only in different namespaces, this is most obvious to help. In these cases we have postfix the key with Help.

If you want you can use this node script to help with the migration. It will take all the single files and put them into a new one and also take care of some of the mapping:

import { readFileSync, writeFileSync, appendFileSync } from "node:fs";

const ns = [
  "common",
  "common-help",
  "dashboard",
  "clients",
  "clients-help",
  "client-scopes",
  "client-scopes-help",
  "groups",
  "realm",
  "roles",
  "users",
  "users-help",
  "sessions",
  "events",
  "realm-settings",
  "realm-settings-help",
  "authentication",
  "authentication-help",
  "user-federation",
  "user-federation-help",
  "identity-providers",
  "identity-providers-help",
  "dynamic",
];

const map = new Map();
const dup = [];

ns.forEach((n) => {
  const rawData = readFileSync(n + ".json");
  const translation = JSON.parse(rawData);
  Object.entries(translation).map((e) => {
    const name = e[0];
    const value = e[1];
    if (map.has(name) && map.get(name) !== value) {
      if (n.includes("help")) {
        map.set(name + "Help", value);
      } else {
        map.set(name, value);
        dup.push({
          name: name,
          value: map.get(name),
          dup: { ns: n, value: value },
        });
      }
    } else {
      map.set(name, value);
    }
  });
});

writeFileSync(
  "translation.json",
  JSON.stringify(Object.fromEntries(map.entries()), undefined, 2),
);

const mapping = [
  ["common:clientScope", "clientScopeType"],
  ["identity-providers:createSuccess", "createIdentityProviderSuccess"],
  ["identity-providers:createError", "createIdentityProviderError"],
  ["clients:createError", "createClientError"],
  ["clients:createSuccess", "createClientSuccess"],
  ["user-federation:createSuccess", "createUserProviderSuccess"],
  ["user-federation:createError", "createUserProviderError"],
  ["authentication-help:name", "flowNameHelp"],
  ["authentication-help:description", "flowDescriptionHelp"],
  ["clientScopes:noRoles", "noRoles-clientScope"],
  ["clientScopes:noRolesInstructions", "noRolesInstructions-clientScope"],
  ["users:noRoles", "noRoles-user"],
  ["users:noRolesInstructions", "noRolesInstructions-user"],
  ["clients:noRoles", "noRoles-client"],
  ["clients:noRolesInstructions", "noRolesInstructions-client"],
  ["groups:noRoles", "noRoles-group"],
  ["groups:noRolesInstructions", "noRolesInstructions-group"],
  ["roles:noRoles", "noRoles-roles"],
  ["roles:noRolesInstructions", "noRolesInstructions-roles"],
  ["realm:realmName:", "realmNameField"],
  ["client-scopes:searchFor", "searchForClientScope"],
  ["roles:searchFor", "searchForRoles"],
  ["authentication:title", "titleAuthentication"],
  ["events:title", "titleEvents"],
  ["roles:title", "titleRoles"],
  ["users:title", "titleUsers"],
  ["sessions:title", "titleSessions"],
  ["client-scopes:deleteConfirm", "deleteConfirmClientScopes"],
  ["users:deleteConfirm", "deleteConfirmUsers"],
  ["groups:deleteConfirm_one", "deleteConfirmGroup_one"],
  ["groups:deleteConfirm_other", "deleteConfirmGroup_other"],
  ["identity-providers:deleteConfirm", "deleteConfirmIdentityProvider"],
  ["realm-settings:deleteConfirm", "deleteConfirmRealmSetting"],
  ["roles:whoWillAppearLinkText", "whoWillAppearLinkTextRoles"],
  ["users:whoWillAppearLinkText", "whoWillAppearLinkTextUsers"],
  ["roles:whoWillAppearPopoverText", "whoWillAppearPopoverTextRoles"],
  ["users:whoWillAppearPopoverText", "whoWillAppearPopoverTextUsers"],
  ["client-scopes:deletedSuccess", "deletedSuccessClientScope"],
  ["identity-providers:deletedSuccess", "deletedSuccessIdentityProvider"],
  ["realm-settings:deleteSuccess", "deletedSuccessRealmSetting"],
  ["client-scopes:deleteError", "deletedErrorClientScope"],
  ["identity-providers:deleteError", "deletedErrorIdentityProvider"],
  ["realm-settings:deleteError", "deletedErrorRealmSetting"],
  ["realm-settings:saveSuccess", "realmSaveSuccess"],
  ["user-federation:saveSuccess", "userProviderSaveSuccess"],
  ["realm-settings:saveError", "realmSaveError"],
  ["user-federation:saveError", "userProviderSaveError"],
  ["realm-settings:validateName", "validateAttributeName"],
  ["identity-providers:disableConfirm", "disableConfirmIdentityProvider"],
  ["realm-settings:disableConfirm", "disableConfirmRealm"],
  ["client-scopes:updateSuccess", "updateSuccessClientScope"],
  ["client-scopes:updateError", "updateErrorClientScope"],
  ["identity-providers:updateSuccess", "updateSuccessIdentityProvider"],
  ["identity-providers:updateError", "updateErrorIdentityProvider"],
  ["user-federation:orderChangeSuccess", "orderChangeSuccessUserFed"],
  ["user-federation:orderChangeError", "orderChangeErrorUserFed"],
  ["authentication-help:alias", "authenticationAliasHelp"],
  ["authentication-help:flowType", "authenticationFlowTypeHelp"],
  ["authentication:createFlow", "authenticationCreateFlowHelp"],
  ["client-scopes-help:rolesScope", "clientScopesRolesScope"],
  ["client-scopes-help:name", "scopeNameHelp"],
  ["client-scopes-help:description", "scopeDescriptionHelp"],
  ["client-scopes-help:type", "scopeTypeHelp"],
  ["clients-help:description", "clientDescriptionHelp"],
  ["clients-help:clientType", "clientsClientTypeHelp"],
  ["clients-help:scopes", "clientsClientScopesHelp"],
  ["common:clientScope", "clientScopeTypes"],
  ["dashboard:realmName", "realmNameTitle"],
  ["common:description", "description"],
];

mapping.forEach((m) => {
  const key = m[0].split(":");
  try {
    const data = readFileSync(key[0] + ".json");
    const translation = JSON.parse(data);
    const value = translation[key[1]];
    if (value) {
      appendFileSync(
        "translation.json",
        '"' + m[1] + '": ' + JSON.stringify(value) + ',\n',
      );
    }
  } catch (error) {
    console.error("skipping namespace key: " + key);
  }
});

Save this into a file called transform.mjs in your public/locale/<language> folder and run it with:

node ./transform.mjs
This might not do a complete transform, but very close to it.

Migrating to 22.0.4

A new parameter for specify max length of email local part

A new parameter --spi-user-profile-declarative-user-profile-max-email-local-part-length is added to set max email local part length taking backwards compatibility into consideration. The default value is 64. Example of usage:

kc.[sh|bat] start --spi-user-profile-declarative-user-profile-max-email-local-part-length=100 ...

Migrating to 22.0.2

Never expires option removed from client advanced settings combos

The option Never expires is now removed from all the combos of the Advanced Settings client tab. This option was misleading because the different lifespans or idle timeouts were never infinite, but limited by the general user session or realm values. Therefore, this option is removed in favor of the other two remaining options: Inherits from the realm settings (the client uses general realm timeouts) and Expires in (the value is overridden for the client). Internally the Never expires was represented by -1. Now that value is shown with a warning in the Admin Console and cannot be set directly by the administrator.

New LinkedIn OpenID Connect social provider

A new social identity provider called LinkedIn OpenID Connect has been introduced for the business and employment-focused platform. LinkedIn released recently a new product for developers called Sign In with LinkedIn using OpenID Connect. The product provides a new way to authenticate members using OpenID Connect, but the default OpenID Connect v1.0 identity provider does not work with it at present time. For that reason, Keycloak adds this new identity provider as the specific social provider for the new product.

The old LinkedIn way based on OAuth seems to be completely removed from the developer portal. How the existing LinkedIn social provider is working with current applications is not clear. Keycloak maintains the old provider renamed to LinkedIn (deprecated), but in a deprecated feature called linkedin-oauth which is disabled by default. It will be removed in future versions. Please enable it again at startup if needed:

kc.[sh|bat] start --features linkedin-oauth ...

Migrating to 22.0.0

Transition from Java EE to Jakarta EE

Keycloak migrated its codebase from Java EE (Enterprise Edition) to its successor Jakarta EE, which brings various changes into Keycloak.

We have upgraded all Jakarta EE specifications in order to support Jakarta EE 10, such as:

  • Jakarta Persistence 3.1

  • Jakarta RESTful Web Services 3.1

  • Jakarta Mail API 2.1

  • Jakarta Servlet 6.0

  • Jakarta Activation 2.1

Jakarta EE 10 provides a modernized, simplified, lightweight approach to building cloud-native Java applications. The main changes provided within this initiative are changing the namespace from javax.* to jakarta.*. It does not apply for javax.* packages provided directly in the JDK, such as javax.security, javax.net, javax.crypto, etc.

You can be affected by these changes in your custom extensions, providers or JPA entities.

Upgrade to Quarkus 3

Keycloak upgraded to version 3 of the Quarkus Java framework. Quarkus 3 continues the tradition of propelling Java development by moving fast and providing a cutting-edge user experience with the latest technologies. It continues to improve overall performance and efficiency.

Quarkus 3 is based on Jakarta EE 10, the same as Keycloak, creating smooth interoperability between them. In addition, it contains Eclipse MicroProfile 6, which aligns with Jakarta EE 10 Core Profile. The central part of the Quarkus 3 upgrade is built-in support for JPA 3.1 and Hibernate ORM 6.

quarkus.hibernate-orm.* properties no longer working

For Quarkus 3, Hibernate ORM configurations must be specified in either the persistence.xml file or in Quarkus properties, but not in both places. Keycloak uses a persistence.xml file, therefore, it is no longer possible to override Keycloak’s JPA store configurations via Quarkus’ configuration properties for the default persistence unit whose names start with quarkus.hibernate-orm.

Upgrade to Hibernate ORM 6

Keycloak now benefits from the upgrade to Hibernate ORM 6.2, which includes improved performance, better SQL, modern JDK support, and support for modern RDBMS features. The performance improvements primarily affect JDBC, HQL Translation, and Criteria Translation.

If you have custom providers or JPA entities, these changes may affect you.

We recommend reviewing the Quarkus migration guide or the Hibernate release notes for more information.

Legacy Promise API removed from Keycloak JS adapter

The legacy Promise API methods have been removed from the Keycloak JS adapter. This means that calling .success() and .error() on promises returned from the adapter is no longer possible. Instead standardized Promise methods such as .then() and .catch() should be used.

Before migration:
const keycloak = new Keycloak();

keycloak.init()
  .success(function(authenticated) {
    alert(authenticated ? 'authenticated' : 'not authenticated');
  }).error(function() {
    alert('failed to initialize');
  });
After migration:
const keycloak = new Keycloak();

keycloak.init()
  .then(function(authenticated) {
    alert(authenticated ? 'authenticated' : 'not authenticated');
  }).catch(function() {
    alert('failed to initialize');
  });
Or alternatively, when using the await keyword to unwrap these promises:
const keycloak = new Keycloak();

try {
  const authenticated = await keycloak.init();
  alert(authenticated ? 'authenticated' : 'not authenticated');
} catch (error) {
  alert('failed to initialize');
}

Export and Import perform an automatic build

In previous releases, the export and import commands required a build command to be run first. Starting with this release, the export and import commands perform an automatic rebuild of Keycloak if a build time configuration has changed.

When migrating existing scripts that run a build command first, migrate by adding the --optimized command line option to the export and import command to avoid Keycloak automatically re-building the image. Not adding the --optimized option in this might make Keycloak trigger a rebuild and revert to the default values, and then connecting to the database for export and import will not work.

The following examples assume that runtime parameters like a database password are provided via a configuration file or an environment variable.

Before migration: Running the build command before running the export command
bin/kc.[sh|bat] build --db=postgres ...
bin/kc.[sh|bat] export --dir <dir>
After migration: Adding --optimized to the export command
bin/kc.[sh|bat] build --db=postgres ...
bin/kc.[sh|bat] export --optimized --dir <dir>
After migration: Leveraging the auto-build functionality
bin/kc.[sh|bat] export --dir <dir> --db=postgres ...
NOTE

When the auto-build runs, the build time options will be in effect for all subsequent commands that are started with the --optimized flag, including the start command.

In previous releases the export and import commands allowed runtime parameters such as a database URL only in configuration files or environment variables. Starting with this release, those runtime parameters are now available on the command line as well. Use the --help option to find out about the supported parameters.

Renamed Keycloak Admin client artifacts

After the upgrade to Jakarta EE, artifacts for Keycloak Admin clients were renamed to more descriptive names with consideration for long-term maintainability. We still provide two separate Keycloak Admin clients, one with Jakarta EE and the other with Java EE support.

We stopped releasing the org.keycloak:keycloak-admin-client-jakarta artifact. The default one for the Keycloak Admin client with Jakarta EE support is org.keycloak:keycloak-admin-client (since version 22.0.0).

The new artifact with Java EE support is org.keycloak:keycloak-admin-client-jee.

Jakarta EE support
Before migration:
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-admin-client-jakarta</artifactId>
    <version>21.0.0</version>
</dependency>
After migration:
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-admin-client</artifactId>
    <version>22.0.0</version>
</dependency>
Java EE support
Before migration:
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-admin-client</artifactId>
    <version>21.0.0</version>
</dependency>
After migration:
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-admin-client-jee</artifactId>
    <version>22.0.0</version>
</dependency>

Passthrough proxy mode changes

Keycloak’s proxy configuration setting for mode passthrough no longer parses HTTP forwarding headers in the request, as when a proxy forwards an HTTPS connection in passthrough mode, a proxy is unable to add, remove or update HTTP headers.

Installations that want the HTTP headers in the client’s request to be parsed should use the edge or reencrypt setting.

See Using a reverse proxy for details.

Consistent fallback message resolving for all themes

This change only may affect you when you are using realm localization messages.

Up to this version, the resolving of fallback messages was inconsistent across themes, when realm localization messages were used. More information can be found in the following issue.

The implementation has now been unified for all themes. In general, the message for the most specific matching language tag has the highest priority. If there are both a realm localization message and a Theme 18n message, the realm localization message has the higher priority. Summarized, the priority of the messages is as follows (RL = realm localization, T = Theme i18n files): RL <variant> > T <variant> > RL <region> > T <region> > RL <language> > T <language> > RL en > T en.

Probably this can be better explained with an example: When the variant de-CH-1996 is requested and there is a realm localization message for the variant, this message will be used. If such a realm localization message does not exist, the Theme i18n files are searched for a corresponding message for that variant. If such a message does not exist, a realm localization message for the region (de-CH) will be searched. If such a realm localization message does not exist, the Theme i18n files are searched for a message for that region. If still no message is found, a realm localization message for the language (de) will be searched. If there is no matching realm localization message, the Theme i18n files are be searched for a message for that language. As last fallback, the English (en) translation is used: First, an English realm localization will be searched - if not found, the Theme 18n files are searched for an English message.

UserQueryProvider changes

UserQueryProvider interface was split into two. One is UserQueryMethodsProvider providing capabilities for querying users. Second one is UserCountMethodsProvider which provides capability for counting number of users in particular storage.

Keycloak now has the ability to differentiate between user storage providers that can efficiently execute count queries and those that cannot. The UserQueryProvider interface still exists and extends both new interfaces. Therefore, there is no need for any modifications in the existing implementations of UserQueryProvider since it retains the same methods.

LDAPStorageProvider search changes

Starting with this release Keycloak uses a pagination mechanism when querying federated LDAP database. Searching for users should be consistent with search in local database.

Since this release LDAPStorageProvider implements only UserQueryMethodsProvider, not UserQueryProvider.

Deprecation of Keycloak OpenID Connect Adapters

Starting with this release, we no longer will invest our time on the following Keycloak OpenID Connect Adapters:

  • Keycloak Wildfly OpenID Connect Adapter

  • Keycloak JEE Servlet OpenID Connect Adapter

  • Keycloak Spring Boot and Spring Security OpenID Connect Adapter

This move is already reflected in our documentation and in our quickstart repository. Please, consider looking at the following references for more information:

We recommend starting to look into moving your applications to the alternatives from the references above. Those adapters should not be available anymore in future releases.

Deprecation of Keycloak JEE SAML Adapter

The Keycloak JEE SAML Adapter has been discontinued, and we will no longer invest our time on its development following this release.

The official adapter is now based on Jakarta and should be used as soon as you switch your applications to this technology.

This change is already in our documentation and in our quickstart repository. For more information, please consider looking at the following references:

If you cannot migrate your applications to Jakarta, you can still use the "legacy" SAML JEE adapter and still be able to integrate with future releases of the server. However, consider upgrading your applications as soon as possible because we are no longer providing support to JEE.

Changes for openshift-integration feature

The preview feature openshift-integration was removed from Keycloak codebase and moved into separate extension. This includes moving of related providers such as custom client storage provider and token review endpoint for Openshift integration.

If you used this feature, you should not use the openshift-integration feature anymore when starting Keycloak server and instead you need to deploy the JAR file from custom extension. You can check the Openshift extension and the instructions in it’s README file for how to deploy the extension to your Keycloak server.

The Openshift extension is not officially supported and maintained by Keycloak team. You can use it only at your own risk.
Http Challenge flow removed

The built-in authentication flow http challenge was removed along with the authenticator implementations no-cookie-redirect, basic-auth, and basic-auth-otp. The http challenge authentication flow was also intended for Openshift integration and therefore it was removed along with other related capabilities as described above. Authenticator implementations were moved to the Openshift extension described in the previous paragraph.

If you use the http challenge flow as a realm flow or as First Broker Login or Post Broker Login flow for any of your identity providers, the migration is not possible. Be sure to update your realm configuration to eliminate the use of the http challenge flow before migration. If you use the http challenge flow as Authentication Flow Binding Override for any client, the migration would complete, but you could no longer log in to that client. After the migration, you would need to re-create the flow and update the configuration of your clients to use the new/differentJson flow.

Removing third party dependencies

The removal of openshift-integration allows us to remove few third party dependencies from Keycloak distribution. This includes openshift-rest-client, okio-jvm, okhttp, commons-lang, commons-compress, jboss-dmr and kotlin-stdlib. This means that if you use any of these libraries as dependencies of your own providers deployed to Keycloak server, you may also need to copy those jar files explicitly to the Keycloak distribution providers directory as well.

Context and dependency injection no longer enabled to JAX-RS Resources

In order to provide a better runtime and leverage as much as possible the underlying stack, all injection points for contextual data using the javax.ws.rs.core.Context annotation were removed. The expected improvement in performance involves no longer creating proxies instances multiple times during the request lifecycle, and drastically reducing the amount of reflection code at runtime.

If you are extending one of the following SPIs:

  • PolicySpi

  • AdminRealmResourceSpi

  • IdentityProviderSpi

  • RealmResourceSPI

You should review your custom JAX-RS (sub)resources in order to obtain any contextual data as follows:

KeycloakSession session = org.keycloak.common.util.Resteasy.getContextData(KeycloakSession.class);

If you need access to the current request and response objects, you can now obtain their instances directly from the KeycloakSession:

@Context
org.jboss.resteasy.spi.HttpRequest request;
@Context
org.jboss.resteasy.spi.HttpResponse response;

was replaced by:

KeycloakSession session = // obtain the session, which is usually available when creating a custom provider from a factory
KeycloakContext context = session.getContext();

HttpRequest request = context.getHttpRequest();
HttpResponse response = context.getHttpResponse();

In case you have no access to a KeycloakSession instance when invoking a JAX-RS resource method, you can obtain contextual data from the JAX-RS runtime as follows:

KeycloakSession session = org.keycloak.common.util.Resteasy.getContextData(KeycloakSession.class);

Additional contextual data can be obtained from the runtime through the KeycloakContext instance:

KeycloakSession session = // obtain the session
KeycloakContext context = session.getContext();
MyContextualObject myContextualObject = context.getContextObject(MyContextualObject.class);

Upgrading your custom JAX-RS resources

If you are extending the server’s REST APIs through the following SPIs:

  • PolicySpi

  • AdminRealmResourceSpi

  • IdentityProviderSpi

  • RealmResourceSPI

You need to add an empty META-INF/beans.xml to the JAR file where your custom providers are packaged. Otherwise, they are not recognized by the server at runtime.

If you are using RealmResourceSPI or AdminRealmResourceSpi, you have the choice between adding an empty file named beans.xml under META-INF or annotating the JAX-RS resource classes with the jakarta.ws.rs.ext.Provider annotation.

You should also make sure your JAX-RS methods are declaring the expected media types for input and output by marking them with the @Consumes and @Produces annotations, respectively.

Deprecated methods from data providers and models

In earlier versions of Keycloak, provider and model interfaces underwent a cleanup process that involved deprecating certain methods. In this release the methods were removed and some additional methods were deprecated. The Javadoc for these methods from Keycloak 21 included information about their corresponding replacements.

  • RealmModel#searchForGroupByNameStream(String, Integer, Integer) was removed.

  • UserProvider#getUsersStream(RealmModel, boolean) was removed.

  • UserSessionPersisterProvider#loadUserSessions(int, int, boolean, int, String) was removed.

  • Interfaces added for Streamification work were removed. Such as RoleMapperModel.Streams and similar.

  • Streams interfaces in federated storage provider classes were deprecated.

  • KeycloakModelUtils#getClientScopeMappings was removed.

  • Deprecated methods from KeycloakSession were removed.

  • UserQueryProvider#getUsersStream methods were removed.

Multiple Keycloak instances

Multiple Keycloak CRs may be created in the same namespace and will be managed independently by the operator. To allow for this StatefulSets created by older versions of the operator must be re-created. This will happen automatically when the operator is upgraded and lead to small amount of downtime.

k8s.keycloak.org/v2alpha1 changes

The condition status field was changed from a boolean to a string for conformance with standard Kubernetes conditions. In the CRD it will temporarily be represented as accepting any content, but it will only ever be a string. Please make sure any of your usage of this field is updated to expect the values "True", "False", or "Unknown", rather than true or false.

Keycloak supports IPv4/IPv6 dual stack

Keycloak supports the IPv4/IPv6 dual stack and can be accessible by default via the IPv4 and IPv6 addresses. In the older versions of Keycloak, the default approach was to use only IPv4 addresses.

Migrating to 21.1.0

Javascript engine available by default on the classpath

In the previous version, when Keycloak was used on Java 17 with Javascript providers (Script authenticator, Javascript authorization policy or Script protocol mappers for OIDC and SAML clients), it was needed to copy javascript engine to the distribution. This is no longer needed as Nashorn javascript engine is available in Keycloak server by default. When you deploy script providers, it is recommended to not copy the nashorn script engine and it’s dependencies into the Keycloak distribution.

Change of the default Client ID mapper of Service Account Client

Default Client ID mapper of Service Account Client has been changed. Token Claim Name field value has been changed from clientId to client_id. client_id claim is compliant with OAuth2 specifications:

clientId userSession note still exists.

Keycloak JS adapter must be instantiated with the new operator

Historically it has been possible to create an instance of the Keycloak JS adapter by calling the Keycloak() function directly:

const keycloak = Keycloak();

To align this with modern conventions in the JavaScript world it has been possible to use the new operator to create an instance instead:

const keycloak = new Keycloak();

The function-style constructor has been deprecated for a while, but starting this version we will actively log a deprecation message when it used. This style of constructor will be removed in a future version so make sure to migrate your code to use the new operator.

Migrating to 21.0.2

Terms and Conditions user attribute migration

The terms_and_conditions user attribute was accidentally changed in 21.0.0 to uppercase. This version reverts the user attribute back to lowercase. The value of the attribute is set when accepting Terms and Conditions page.

If any of your custom extensions relies on this attribute, you may need to adjust your code to check both attributes terms_and_conditions and TERMS_AND_CONDITIONS.

Migrating to 21.0.0

Keycloak uses Micrometer for metrics

Keycloak provides an optional a metrics endpoint which exports metrics in the Prometheus format. In this release the implementation to provide this data switched from SmallRye to Micrometer, which is the recommended metrics library for Quarkus.

Due to this change, metrics have been renamed. The following table shows some examples.

Before upgrading it is recommended to review all metrics returned from the endpoint before and after the change, and update their usage in dashboards and alerts.

Table 1. Examples of changed metrics names
Old metric name New metric name

base_gc_total

jvm_gc_pause_seconds_count

base_gc_time_total_seconds

jvm_gc_pause_seconds_sum

base_thread_count

jvm_threads_live_threads

vendor_agroal_*

agroal_*

Deprecated RSA_SHA1 and DSA_SHA1 algorithms for SAML

Algorithms RSA_SHA1 and DSA_SHA1, which can be configured as Signature algorithms on SAML adapters, clients and identity providers are deprecated. We recommend to use safer alternatives based on SHA256 or SHA512. Also, verifying signatures on signed SAML documents or assertions with these algorithms do not work on Java 17 or higher. If you use this algorithm and the other party consuming your SAML documents is running on Java 17 or higher, verifying signatures will not work.

The possible workaround is to remove algorithms such as http://www.w3.org/2000/09/xmldsig#rsa-sha1 or http://www.w3.org/2000/09/xmldsig#dsa-sha1 from the list of "disallowed algorithms" configured on property jdk.xml.dsig.secureValidationPolicy in the file $JAVA_HOME/conf/security/java.security.

SAML SP metadata changes

In this version, Keycloak will refuse to decrypt assertions encrypted using a realm key generated for signing purpose. This change means all encrypted communication from IDP to SP (where Keycloak acts as the SP) will stop working.

There are two ways to make this work:

  • either update the IDP configuration with the metadata generated by a newer version of Keycloak,

  • or run Keycloak in backward compatibility mode that will make Keycloak work with the metadata generated by older Keycloak versions. This mode can be enabled using -Dkeycloak.saml.deprecated.encryption=true flag. Note this backward compatibility mode is planned to be removed in Keycloak 24.

Deprecated methods from user session provider were removed

In Keycloak 13 there was introduced UserLoginFailureProvider and some methods from UserSessionProvider were moved there. The methods in UserSessionProvider were deprecated and now has been removed. Javadoc of these methods contained a corresponding replacement (see Javadoc of Keycloak 20 release).

Custom themes using old admin console won’t work

The old admin console, which was deprecated in previous versions, was finally removed. This also means that your custom themes, which were using it as parent theme or importing from it, won’t work. It is highly recommended to not deploy such themes at all as extending old admin console is not applicable anymore and there can be issues in Keycloak (at least warnings or errors in the logs) with such themes deployed.

Curl has been removed from the container

The Keycloak Container Image has been modified to enhance security. As a result, curl and other CLI tools have been removed, which you may have been using in your customized image. See the updated container guide for information on how to handle this change.

Migrating to 20.0.0

RESTEasy Version Update

Updated the RESTEasy version of Keycloak Admin REST Client to the next major version.

H2 Version Update

Keycloak ships for development purposes with an H2 database driver. As it is intended for development purposes only, it should never be used in a production environment.

In this release, the H2 driver has been upgraded from version 1.x to version 2.x. This change might require changes to the H2 JDBC URL or migration of the H2 database files in an existing Keycloak setup.

Changes to the H2 JDBC URL

For Keycloak to run with its JPA legacy store with H2 version 2.x, the JDBC URL requires the attribute NON_KEYWORDS=VALUE.

In a setup where H2 is initialized by Keycloak without extra parameters, Keycloak will append the attribute automatically. This is the default for development setups.

If an H2 JDBC URL is provided on the command line or in a configuration file, and it already contains the NON_KEYWORDS= attribute in the JDBC URL, this attribute needs to be amended with the VALUE keyword.

If the connection factory for the H2 database is initialized outside Keycloak, that initialization needs to take care of adding the NON_KEYWORDS attribute.

See the H2 documentation on the NON_KEYWORDS attribute for details.

Upgrade of H2 database files

H2 database base files created with H2 version 1.x should not be used with version 2.x.

Purge existing H2 database files to start with an empty database, export and import the realms using Keycloak’s export and import functionality, or refer to the migration notes on the H2 database project’s website for details on how to migrate H2 database contents.

Breaking changes in the new version of Keycloak Operator

In order to use the newest version of the Keycloak Operator, the manual reinstallation and upgrade of your CRs are required. There’s no automated migration.

This release contains the following breaking changes in Keycloak CRs:

serverConfiguration free-form field was renamed

From now on it’s called additionalOptions. The idea behind this decision is to align it more with the Keycloak Quarkus distribution and achieve/preserve a naming consistency. serverConfiguration can be still used for configuring options that haven’t got a declared alternative in Keycloak custom resources (CRs). A good example of such use can be service providers.

Ingress options were refined

In the past, it used to be defined via the disableDefaultIngress property. We decided to clarify it a bit, thus from now on you can use the following structure to control your ingress settings:

spec:
    ...
    ingress:
      enabled: false
HTTP options were added

Similarly, like with ingress, you can define multiple HTTP options in a better structural manner:

spec:
    ...
  http:
    httpEnabled: true
    httpPort: 80
    httpsPort: 443
    tlsSecret: my-tls-secret
Hostname options were added

Last but not least, the hostname options were also changed:

spec:
    ...
  hostname:
    hostname: [keycloak-server-hostname]
    admin: [admin-console-hostname]
    adminUrl: [admin-console-base-url]
    strict: [true|false]
    strictBackchannel: [true|false]
Some fields are no longer required

The hostname and tlsSecret fields are now optional to align with the Quarkus distribution configuration. With that we also removed the possibility to set INSECURE-DISABLE special value to those fields. In order to disable hostname checks and enable HTTP, please follow the same approach as with the Quarkus distribution, i.e. set strict: false, strictBackchannel: false and httpEnabled: true fields.

OLM channel was changed to fast

The default channel of Keycloak Operator Lifecycle Manager was changed to fast.

Deprecated methods from data providers and models were removed

Prior to Keycloak 15, there was a clean-up of provider and model interfaces where we deprecated some methods. Javadoc of these methods contained a corresponding replacement method (see Javadoc of Keycloak 19 release). In this release the methods were removed. The following is a list of all changed classes.

The most common patterns for deprecating and removing the methods are the following.

  • Streamification - interfaces now contain only Stream-based methods.

    For example in GroupProvider interface

    @Deprecated
    List<GroupModel> getGroups(RealmModel realm);

    was replaced by

    Stream<GroupModel> getGroupsStream(RealmModel realm);

    More details on streamification work can be found in KEYCLOAK-14011.

  • Consistent parameter ordering - methods now have strict parameter ordering where RealmModel is always the first parameter.

    For example in UserLookupProvider interface

    @Deprecated
    UserModel getUserById(String id, RealmModel realm);

    was replaced by

    UserModel getUserById(RealmModel realm, String id)
List of changed interfaces

(o.k. stands for org.keycloak. package)

  • server-spi module

    • o.k.credential.CredentialInputUpdater

    • o.k.credential.UserCredentialStore

    • o.k.models.ClientProvider

    • o.k.models.ClientSessionContext

    • o.k.models.GroupModel

    • o.k.models.GroupProvider

    • o.k.models.KeyManager

    • o.k.models.KeycloakSessionFactory

    • o.k.models.ProtocolMapperContainerModel

    • o.k.models.RealmModel

    • o.k.models.RealmProvider

    • o.k.models.RoleContainerModel

    • o.k.models.RoleMapperModel

    • o.k.models.RoleModel

    • o.k.models.RoleProvider

    • o.k.models.ScopeContainerModel

    • o.k.models.UserCredentialManager

    • o.k.models.UserModel

    • o.k.models.UserProvider

    • o.k.models.UserSessionProvider

    • o.k.models.utils.RoleUtils

    • o.k.sessions.AuthenticationSessionProvider

    • o.k.storage.client.ClientLookupProvider

    • o.k.storage.group.GroupLookupProvider

    • o.k.storage.user.UserLookupProvider

    • o.k.storage.user.UserQueryProvider

  • server-spi-private module

    • o.k.events.EventQuery

    • o.k.events.admin.AdminEventQuery

    • o.k.keys.KeyProvider

All changes are linked to the following issue.

Migrating to 19.0.2

OpenID Connect Logout Prompt

At Keycloak 18.0.0, the logout is now compatible with the new OIDC specification, which changed the handling for the url parameters. However, to also remain compatible with earlier versions, a compatibility flag is introduced. See the Upgrading Guide for further information for the backwards compatibility option, which allows your application to still use the old format for the url parameters.

While the url parameters can now be configured to be compatible, there was still one incompatibility with keycloak 17 and earlier releases. If the user does not provide a valid idTokenHint, a logout prompt appears instead of a successful logout redirect. Therefore, a new compatibility flag suppress-logout-confirmation-screen is introduced to suppress the logout screen.

You can enable this parameter when you start the server by entering the following command:

bin/kc.[sh|bat] --spi-login-protocol-openid-connect-suppress-logout-confirmation-screen=true start

With this configuration, you can still use the logout endpoint without a user prompt.

The backwards compatibility switch will be removed in some future version - probably Keycloak 23. You are encouraged to update your clients as soon as possible as described above rather than rely on this switch.

Deploying scripts through SAML javascript protocol mapper

Until now, administrators, which used SAML javascript protocol mapper on their SAML clients or client scopes, were allowed to upload scripts to the server through the Keycloak Administration Console as well as through the RESTful Admin API.

For now on, this capability is disabled and users should deploy scripts directly to the server. This behaviour is aligned with other script based providers. For more details, please take a look at JavaScript Providers.

UserInfo Endpoint Changes

Error response changes

The UserInfo endpoint is now returning error responses fully compliant with RFC 6750 (The OAuth 2.0 Authorization Framework: Bearer Token Usage). Error code and description (if available) are provided as WWW-Authenticate challenge attributes rather than JSON object fields. The responses will be the following, depending on the error condition:

  • In case no access token is provided:

    401 Unauthorized
    WWW-Authenticate: Bearer realm="myrealm"
  • In case several methods are used simultaneously to provide an access token (for example, Authorization header + POST access_token parameter), or POST parameters are duplicated:

    400 Bad Request
    WWW-Authenticate: Bearer realm="myrealm", error="invalid_request", error_description="..."
  • In case an access token is missing openid scope:

    403 Forbidden
    WWW-Authenticate: Bearer realm="myrealm", error="insufficient_scope", error_description="Missing openid scope"
  • In case of inability to resolve cryptographic keys for UserInfo response signing/encryption:

    500 Internal Server Error
  • In case of a token validation error, a 401 Unauthorized is returned in combination with the invalid_token error code. This error includes user and client related checks and actually captures all the remaining error cases:

    401 Unauthorized
    WWW-Authenticate: Bearer realm="myrealm", error="invalid_token", error_description="..."
Other Changes
  • It is now required for access tokens to have the openid scope, which is stipulated by UserInfo being a feature specific to OpenID Connect and not OAuth 2.0. If the openid scope is missing from the token, the request will be denied with a 403 Forbidden (see above).

  • UserInfo now checks the user status, and returns the invalid_token response if the user is disabled.

Migrating to 19.0.0

New Admin Console is now the default console

The new admin console is now the default console in Keycloak. If you are not able to start using the new admin console it is possible to continue to use the old admin console by disabling the new console, by for example running:

bin/kc.sh start-dev --features-disabled=admin2

An alternative approach to continue using the old admin console is to set the theme for the master realm or any other realm to keycloak.

As the new admin console is significantly different to the old admin console, is now based on React and uses a newer version of PatternFly, any custom themes will most likely have to be re-implemented from scratch. To create a custom theme for the new admin console the theme should extend keycloak.v2 instead of keycloak.

If you have explicitly set the admin console theme to keycloak for the master realm or any other realm, it will continue to use the old admin console. To update to the new admin console you need to change the theme to keycloak.v2.

The old admin console will be removed in Keycloak 21.

Changes to the server configuration and startup

Before this release, you would use the --auto-build when running the start command to tell the server to conditionally run a build if any build option has changed prior to starting the server.

In this release, the --auto-build flag is deprecated and you no longer need to use it to indicate that you want to set build options when starting the server. Instead, the server is always going to run a build by default prior to starting the server if any build option has changed. The new behavior improves the overall experience when configuring and starting the server by making it optional, although highly recommended, to run a build command beforehand in order to achieve the best startup time and memory footprint.

Now, in order to achieve the best startup time and memory footprint, set the --optimized option to disable the new default behavior. The --optimized flag tells the server that checking for and running a build directly as part of the startup is not needed:

kc.sh start --optimized

If you are already using a custom image to set build options and run an optimized Keycloak container, make sure you set the --optimized option when invoking the start command.

For more details, please take a look at the Configuration Guide and the Containers Guide.

Potentially breaking changes to the health endpoints

Before Keycloak 19.0.0, the quarkus based Keycloak distribution always enabled the following non-application endpoints unintentionally:

  • /q/health

  • /q/health/live

  • /q/health/ready

  • /q/metrics

Starting in Keycloak 19.0.0, these endpoints are disabled and a request will result in a 404 HTTP status-code. If you are using the /q/…​ endpoints, make sure to change your probes and monitoring systems to use the intended health endpoints instead when upgrading to Keycloak 19.0.0.

The intended health endpoints are:

  • /health

  • /health/live

  • /health/ready

  • /metrics

Apart from disabling the /q/ endpoints, these are the other improvements made to the health endpoints:

  • The health/live endpoint used for liveness probes is now decoupled from the database connections health, to match current good practices and to not have the same behaviour as the health/ready endpoint. As a result, the database check is not shown in the checks: array anymore when calling /health/live, so when there is a database hiccup, the liveness probe will still return HTTP status-code 200 and a status of UP, so no pod restart may be triggered.

  • The health/ready endpoint used for readiness probes still checks for a working database connection. Make sure you have not only health-enabled=true but also metrics-enabled=true set in your configuration, to enable the database check, resulting in an effective readiness probe. It will return HTTP status-code 503 and a status of DOWN when the database connection is not in a healthy state.

Expect more enhancements in this area in the future. For more information, see the Health guide

Changes using GELF / centralized log management

As stated in the release notes, Keycloak now supports gelf logging for centralized logging systems out of the box.

When you added the gelf related quarkus jars yourself in a prior version, make sure to switch to the supported configuration options in the logging guide and remove your jars from the providers folder.

Changes affecting developers

Keycloak undergoes large refactoring, which impacts existing code. Some of these changes require updates to existing code. These are in more detailed described below.

Rationale for changes

Keycloak has several limitations; for example, downtime is needed for upgrading a Keycloak cluster. To address the limitations, an in-depth refactor has been initiated.

The changes in this version are mostly attached to storage refactoring and a preparation of a new storage, called map storage. This storage will eventually replace the current storage, which will be called a legacy store with this version. The legacy store will still be available in Keycloak for several more versions.

The new store imposes a strict separation of responsibility between the service and storage layers. For that reason, the service layer’s visibility of an object’s origin will be restricted, so it will not be able to discriminate between cached or non-cached objects, or objects originating from local or federated storage.

User storage SPI will become deprecated. It will be supported for several more versions, but will be eventually replaced by the Map Storage SPI, which will offer the ability to create custom storages for any recognized area, such as users, roles, clients, or groups.

Extensions that rely on the level of detail available to services in the legacy store will need adjustment to retain this ability for the full deprecation period of the legacy store. The following section describes how that adjustment is accomplished.

Using a legacy and map store is mutually exclusive; one store cannot be used while the other is active.

Changes in the module structure

As part of introducing the new storage functionality, several public APIs around storage functionality in KeycloakSession have been consolidated, and some have been deprecated and will be removed in one of the next versions. Three new modules have been introduced, and data-oriented code from server-spi, server-spi-private, and services modules have been moved there:

org.keycloak:keycloak-model-legacy

Contains all public facing APIs from the legacy store, such as the User Storage API.

org.keycloak:keycloak-model-legacy-private

Contains private implementations that relate to user storage management, such as storage *Manager classes.

org.keycloak:keycloak-model-legacy-services

Contains all REST endpoints that directly operate on the legacy store, and have no meaning in the new store.

These modules will be available as long as legacy stores will be supported. After that period, they will be removed.

This change impacts deployments of existing user storage providers in the Wildfly distribution. If your user storage provider is deployed as a WAR archive, you need to add the META-INF/jboss-deployment-structure.xml file into that archive stating the modified dependencies as shown below:

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
    <deployment>
        <dependencies>
            <module name="org.keycloak.keycloak-model-legacy" meta-inf="import"/>
        </dependencies>
    </deployment>
</jboss-deployment-structure>
Changes in KeycloakSession

KeycloakSession has been simplified. Several methods have been deprecated in KeycloakSession and will be removed in a future version.

KeycloakSession session contains several methods for obtaining a provider for a particular object type, such as for a UserProvider there are users(), userLocalStorage(), userCache(), userStorageManager(), and userFederatedStorage(). This situation may be confusing for the developer who has to understand the exact meaning of each method, and depends on current store layout. The new store does not distinguish federated from local storage.

For those reasons, only the users() method will be kept in KeycloakSession, and should replace all other calls listed above. The rest of the methods are deprecated, and will eventually be removed. The same pattern of deprecation applies to methods of other object areas, such as clients() or groups(). All methods ending in *StorageManager() and *LocalStorage() now throw an exception when being called, as there is no direct replacement in the new store. The next section describes how to migrate those calls to the new API or use the legacy API while using the old store.

The deprecated methods in KeycloakSession will be removed in a future release. The keycloak-model-legacy-* modules will be available for a longer time and will eventually be removed.

Migrating existing providers that do not depend on the legacy store

The existing providers need no migration if they do not call a deprecated method, which should be the case for most providers.

If the provider uses deprecated methods, but does not rely on local versus non-local storage, changing a call from the now deprecated userLocalStorage() to the method users() is the best option. Be aware that the semantics change here as the new method involves a cache if that has been enabled in the local setup.

Before migration: accessing a deprecated API that now throws an exception
session.userLocalStorage();
After migration: accessing the new API caller does not depend on the legacy storage API
session.users();
Migrating existing providers that depend on the legacy store

In the rare case when a custom provider needs to distinguish between the mode of a particular provider, access to the deprecated objects is provided by using the LegacyStoreManagers data store provider. This option will be available only if the legacy modules are part of the deployment.

Before migration: accessing a deprecated API that now throws an exception
session.userLocalStorage();
After migration: accessing the old functionality via the LegacyStoreManagers API
((LegacyDatastoreProvider) session.getProvider(DatastoreProvider.class)).userLocalStorage();

Some user storage related APIs have been wrapped in org.keycloak.storage.UserStorageUtil for convenience.

Creating custom storage providers

The API for creating a custom storage provider has not been fully stabilized yet, though it is available as a tech preview. See the MapStorageProvider SPI and its Javadoc for details. The availability of the new API is a priority for the next Keycloak version.

Changes to RealmModel

The methods getUserStorageProviders`, getUserStorageProvidersStream, getClientStorageProviders, getClientStorageProvidersStream, getRoleStorageProviders and getRoleStorageProvidersStream have been removed. Code which depends on these methods and runs with the legacy storage enabled should cast the instance as follows:

Before migration: code will not compile due to the changed API
realm.getClientStorageProvidersStream()...;
After migration: cast the instance to the legacy interface
((LegacyRealmModel) realm).getClientStorageProvidersStream()...;

Similarly, code that used to implement the interface RealmModel and wants to provide these methods should implement the new interface LegacyRealmModel. This interface is a sub-interface of RealmModel and includes the old methods:

Before migration: code implements the old interface
public class MyClass extends RealmModel {
    /* might not compile due to @Override annotations for methods no longer present
       in the interface RealmModel. /
    / ... */
}
After migration: code implements the new interface
public class MyClass extends LegacyRealmModel {
    /* ... */
}
Interface UserCache moved to the legacy module

As the caching status of objects will be transparent to services, the interface UserCache has been moved to the module keycloak-legacy. Calls to session.userCache() will therefore return only a UserProvider, which is a breaking change.

Code that depends on the legacy implementation should access the UserCache directly. While such calls might be necessary while caching with the legacy store is used, it will not be necessary when using the new map store, as that one handles caching transparently.

Before migration: code will not compile due to a changed return type
// session.userCache() might return null, null-check omitted for brevity.
session.userCache().evict(realm, user);
After migration: use the API directly
// session.getProvider(UserCache.class) might return null, null-check omitted for brevity.
session.getProvider(UserCache.class).evict(realm, user);

To trigger the invalidation of a realm, instead of using the UserCache API, consider triggering an event:

Before migration: code will not compile due to a changed return type
UserCache cache = session.getProvider(UserCache.class);
if (cache != null) cache.clear();
After migration: use the invalidation API
session.invalidate(InvalidationHandler.ObjectType.REALM, realm.getId());
Credential management for users

Credentials for users were previously managed using session.userCredentialManager().method(realm, user, ...). The new way is to leverage user.credentialManager().method(...). This form gets the credential functionality closer to the API of users, and does not rely on prior knowledge of the user credential’s location in regard to realm and storage.

The old APIs have been deprecated, and will only work when the legacy storage is enabled in the deployment. The new APIs will work with both old and new storages.

Before migration: accessing a deprecated API
session.userCredentialManager().createCredential(realm, user, credentialModel)
After migration: accessing the new API
user.credentialManager().createStoredCredential(credentialModel)

For a custom UserStorageProvider, there is a new method credentialManager() that needs to be implemented when returning a UserModel. As those providers run in an environment with the legacy storage enabled, those must return an instance of the LegacyUserCredentialManager:

Before migration: code will not compile due to the new method credentialManager() required by UserModel
public class MyUserStorageProvider implements UserLookupProvider, ... {
    /* ... */
    protected UserModel createAdapter(RealmModel realm, String username) {
        return new AbstractUserAdapter(session, realm, model) {
            @Override
            public String getUsername() {
                return username;
            }
        };
    }
}
After migration: implementation of the API UserModel.credentialManager() for the legacy store.
public class MyUserStorageProvider implements UserLookupProvider, ... {
    /* ... */
    protected UserModel createAdapter(RealmModel realm, String username) {
        return new AbstractUserAdapter(session, realm, model) {
            @Override
            public String getUsername() {
                return username;
            }

            @Override
            public SubjectCredentialManager credentialManager() {
                return new LegacyUserCredentialManager(session, realm, this);
            }
        };
    }
}

Deprecated podDisruptionBudget in the legacy Keycloak Operator

With this release, we have deprecated podDisruptionBudget field in the Keycloak CR of the legacy Keycloak Operator. This optional field will be ignored when the Operator is deployed on Kubernetes version 1.25 and higher.

As a workaround, you can manually create the Pod Disruption Budget in your cluster, for example:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  labels:
    app: keycloak
  name: keycloak
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      component: keycloak

See also the Kubernetes Documentation.

Deployment changes in the new Keycloak Operator

The new Keycloak Operator now uses StatefulSet instead of Deployment for Keycloak deployments. There’s no automated migration in place given the Operator is a tech preview in this release. If you are using the new Operator with 18.0.z, please make sure to back up, delete and recreate your Keycloak CR after the upgrade to 19.0.0.

Migrating to 18.0.0

Step-up authentication

Step-up authentication is a new feature. This feature provides the acr client scope, which contains a protocol mapper that is supposed to add the acr claim in the token. The acr claim is not added automatically now as it was before this version, but it is added with the usage of this client scope and protocol mapper.

The client scope is added as a realm "default" client scope and hence will be added to all newly created clients. For performance reasons, the client scope is not automatically added to all existing clients during migration. The clients will not have an acr claim by default after the migration. Consider these possible actions:

  • If you do not plan to use step-up authentication feature, but you rely on the acr claim in the token, you can disable step_up_authentication feature. The claim will be added with the value 1 in case of normal authentication and 0 in case of SSO authentication.

  • Add acr client scope to your clients manually by admin REST API or admin console. This is needed especially if you want to use step-up authentication. If you have a large number of clients in the realm and want to use acr claim for all of them, you can trigger some SQL similar to this against your DB. However, remember to clear the cache or restart the server if Keycloak is already started:

insert into CLIENT_SCOPE_CLIENT (CLIENT_ID, SCOPE_ID, DEFAULT_SCOPE) select CLIENT.ID as CLIENT_ID, CLIENT_SCOPE.ID as SCOPE_ID, true as DEFAULT_SCOPE
from CLIENT_SCOPE, CLIENT where CLIENT_SCOPE.REALM_ID='test' and CLIENT_SCOPE.NAME='acr' and CLIENT.REALM_ID='test' and CLIENT.PROTOCOL='openid-connect';

OpenID Connect Logout

Previous versions of Keycloak had supported automatic logout of the user and redirecting to the application by opening logout endpoint URL such as http(s)://example-host/auth/realms/my-realm-name/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri. While that implementation was easy to use, it had potentially negative impact on performance and security. The new version has better support for logout based on the OpenID Connect RP-Initiated Logout specification. The parameter redirect_uri is no longer supported; also, in the new version, the user needs to confirm the logout. It is possible to omit the confirmation and do automatic redirect to the application when you include parameter post_logout_redirect_uri together with the parameter id_token_hint with the ID Token used for login.

The existing deployments are affected in the following ways:

  • If your application directly uses links to logout endpoint with the redirect_uri parameter, you may be required to change this as described above. Consider either removing the redirect_uri parameter entirely or replacing it with the id_token_hint and post_logout_redirect_uri parameters.

  • If you use java adapters and your application does logout by call httpServletRequest.logout(), you are not affected because this call uses the backchannel variant of the logout endpoint and that one was not changed.

  • If you use the latest javascript adapter, you are also not affected. However if your application uses an older version of the JavaScript adapter, you are affected as this adapter uses the variant of the logout endpoint with the deprecated redirect_uri parameter. In this case, you may need to upgrade to the latest version of the JavaScript adapter.

  • For the Node.js adapter, the same guideline applies as for the JavaScript adapter. You are encouraged to update to the latest version as the older version of the adapter uses the deprecated redirect_uri parameter. With the latest Node.js adapter, you are not affected as long as you use the logout based on the /logout URL as described in the documentation or in the Node.js adapter example. However, in the case when your application directly uses the method keycloak.logoutUrl, you can consider adding idTokenHint as the second argument to this method. The possibility to add idTokenHint as second argument was newly added in this version. The idTokenHint needs to be a valid ID Token that was obtained during the login. Adding idTokenHint is optional, but if you omit it, your users will need to confirm the logout screen as described earlier. Also they will not be redirected back to the application after logout.

There is a backwards compatibility option, which allows your application to still use the old format of the redirect_uri parameter.

You can enable this parameter when you start the server by entering the following command:

bin/kc.[sh|bat] --spi-login-protocol-openid-connect-legacy-logout-redirect-uri=true start

With this configuration, you can still use the format with the redirect_uri parameter. Note the confirmation screen will be needed if the id_token_hint is omitted.

The backwards compatibility switch will be removed in some future version - probably Keycloak 23. You are encouraged to update your clients as soon as possible as described above rather than rely on this switch.

Removal of the upload-scripts feature

Previous versions of Keycloak had supported managing JavaScript code through the management interfaces like the administrations console and REST API. Starting from this version this is no longer possible, and you should now deploy your scripts to the server in order to configure the following providers:

  • OpenID Connect Script Mapper

  • Script Authenticator (Authentication Execution)

  • JavaScript Policies

More details about how to deploy scripts to the server are available in the documentation. Note that to use scripts, you are still required to enable the scripts technology preview feature.

kc.[sh|bat] start --auto-build --features=preview

When deploying scripts, the server is going to automatically create their corresponding providers so that you can select them when configuring authentication flows, mappers, and authorization policies.

In general, the steps to update your realms are the following:

  • Before upgrading, remove any script provider you are using.

  • After the upgrade, deploy your scripts following the instructions in the documentation.

  • Update your authentication flows, mappers, and the client authorization settings to use the providers created from the scripts deployed to the server.

Account console Patternfly upgrade

The Patternfly (PF) React libraries have been updated, @patternfly/react-core from v3.153.3 to v4.147.0, @patternfly/react-icons from v3.15.16 to v 4.11.8, and @patternfly/react-styles from v3.7.14 to v4.11.8. Several minor UI updates were made to bring the account console into alignment with PF design standards.

Custom developed account UIs might not be compatible with these updates due to the breaking changes in PF. Most breaking changes should be resolvable by updating props on PF components.

Resources:

Components known to have breaking changes:

  • Alert

  • action prop changed to actionClose

  • Expandable

  • renamed to ExpandableSection

  • Title

  • size attr now uses TitleSizes

  • DataListContent

  • noPadding changed to hasNoPadding

  • Grid, Stack, Level, Gallery

  • gutter attr changed to hasGutter

  • Modal

  • sizing control changed from, e.g. isLarge, to use ModalVariant, e.g. variant={ModalVariant.large}

  • Select

  • ariaLabelTypeAhead to typeAheadAriaLabel

  • isExpanded to isOpen

  • ariaLabelledBy to aria-labelledby

  • DataListContent

  • noPadding to hasNoPadding

Quarkus distribution: Split metrics-enabled option into health-enabled and metrics-enabled

The metrics-enabled option now only enables the metrics for Keycloak. To enable the readiness and liveness health endpoints, there’s a new boolean option health-enabled. This allows more fine-grained usage of these options, e.g. enabling metrics but not enabling readiness/liveness probes for on-premise use cases. In order to keep the same behaviour as before when metrics-enabled=true was set, you need to additionally set health-enabled=true when building Keycloak.

Migrating to 17.0.0

Default distribution is now powered by Quarkus

The default distribution of Keycloak is now powered by Quarkus, which brings a number of breaking changes to you configure Keycloak and deploy custom providers. For more information check out the Quarkus Migration Guide.

The WildFly distribution of Keycloak is now deprecated, with support ending June 2022. We recommend migrating to the Quarkus distribution as soon as possible. However, if you need to remain on the legacy WildFly distribution for some time, there are some changes to consider:

  • Container images for the legacy distribution tags have changed. To use the legacy distribution use the tags legacy or 17.0.0-legacy.

  • Download on the website for the legacy distribution has changed to keycloak-legacy-17.0.0.[zip|tar.gz].

If you encounter problems migrating to the Quarkus distribution, missing ability to configure something, or have general ideas and feedback, please open a discussion in GitHub Discussions.

Migrating from the preview Quarkus distribution

A number of things have changed since the preview Quarkus distribution was released in Keycloak 15.1.0. The ideal way to learn about what’s changed is to check out the new Server guides. In summary, the changes include:

  • Container now published to quay.io/keycloak/keycloak:latest and quay.io/keycloak/keycloak:17.0.0

  • Download on website renamed to keycloak-17.0.0.[zip|tar.gz].

  • conf/keycloak.properties changed to conf/keycloak.conf, which unifies configuration keys between the config file and CLI arguments.

  • Clearer separation between build options and runtime configuration.

  • Custom Quarkus configuration is done through conf/quarkus.properties.

  • h2-mem and h2-file databases renamed to dev-mem and dev-file.

  • Features are now enabled/disabled with --features and --features-disabled replacing the previous approach that had a separate config key for each feature.

  • Runtime configuration can no longer be passed to kc.[sh|bat] build and is no longer persisted in the build

  • Logging level and format is now configured with --log-level and --log-format, while in the past these had to be configured using unsupported Quarkus properties.

Client Policies Migration : client-scopes

If you used a policy including client-scopes condition and edited JSON document directly, you will need to change the "scope" field name in a JSON document to "scopes".

Liquibase upgraded to version 4.6.2

Liquibase was updated from version 3.5.5 to 4.6.2, which includes, among other things, several bug fixes, and a new way of registering custom extensions using ServiceLoader.

Migration from previous Keycloak versions to Keycloak 17.0.0 has been extensively tested with all currently supported databases, but we would like to stress the importance of closely following the Upgrading Guide, specifically of backing up existing database before upgrade. While we did our best to test the consequences of the Liquibase upgrade, some installations could be using specific setup unknown to us.

Migrating to 16.0.0

WildFly 25 upgrade

WildFly 25 deprecates the legacy security subsystem that among other things was used to configure TLS. Due to the amount of changes we are not able to provide migration scripts as we have done in the past.

We recommend that rather than copying configuration files from previous versions of Keycloak that you start with the default configuration files provided in Keycloak 16 and apply the relevant changes.

Configuration for the Keycloak subsystem can be copied directly.

For more information around the Elytron subsystem refer to the WildFly documentation.

We are really sorry for this inconvenience and understand this will make it significantly harder for everyone to upgrade to Keycloak 16, but we simply have not been able to find an alternative approach.

One thing worth pointing out is the switch to Quarkus distribution, which we plan to make fully supported in Keycloak 17, will make it significantly easier to configure and upgrade Keycloak.

For more information on WildFly 25 refer to the WildFly 25 release notes.

Proxy environment variables

Keycloak now respects the standard HTTP_PROXY, HTTPS_PROXY and NO_PROXY environment variables for outgoing HTTP requests. This change could lead to unexpected use of a proxy server if you have for example the HTTP_PROXY variable defined but have no explicit proxy mappings specified in your SPI configuration. To prevent Keycloak from using those environment variables, you can explicitly create a no proxy route for all requests as .*;NO_PROXY.

Deprecated features in the Keycloak Operator

With this release, we have deprecated and/or marked as unsupported some features in the Keycloak Operator. This concerns the Backup CRD and the operator managed Postgres Database.

Keycloak Operator examples including unsupported Metrics extension

Previously, an unsupported metrics extension was added in the example for the creation of the Keycloak CR by the Keycloak Operator. This has been removed.

Migrating to 14.0.0

Client policies migration

The Client policies feature was a preview feature since Keycloak 12 and did not have proper support. If you tried this feature and configured some client policies or client profiles in Keycloak 12 or Keycloak 13, then you will need to configure your client policies and client profiles again in the new version. The format of the configuration changed significantly as it was only a preview and hence we do not provide automatic migration of client policies and client profiles created in Keycloak 12 or Keycloak 13.

Migrating to 13.0.0

Manual migration step needed

Manual change is required when the standalone.xml contains references to any of the SmallRye modules. SmallRye modules were removed from the underlying WildFly distribution, and the server does not start if the configuration references them. Thus if the configuration in the standalone.xml refers to these modules, the server configuration migration via migrate-standalone.cli fails before any changes are made to the configuration. In such case, to perform server configuration migration, you have to manually remove all the lines that refer to SmallRye modules. In the default configuration, you need to remove specifically the following lines:

<extension module="org.wildfly.extension.microprofile.config-smallrye"/>
<extension module="org.wildfly.extension.microprofile.health-smallrye"/>
<extension module="org.wildfly.extension.microprofile.metrics-smallrye"/>
<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0"/>
<subsystem xmlns="urn:wildfly:microprofile-health-smallrye:2.0" security-enabled="false" empty-liveness-checks-status="${env.MP_HEALTH_EMPTY_LIVENESS_CHECKS_STATUS:UP}" empty-readiness-checks-status="${env.MP_HEALTH_EMPTY_READINESS_CHECKS_STATUS:UP}"/>
<subsystem xmlns="urn:wildfly:microprofile-metrics-smallrye:2.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:wildfly}"/>

Upgrade to Wildfly 23

The Keycloak server was upgraded to use Wildfly 23 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 23 server. For example, Infinispan is now 11.0.9.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically. However, here are the most important changes, which you may need if you made your own configuration changes:

  • The module attribute of Infinispan cache containers is now deprecated (unused) and is replaced with the modules attribute, representing the set of modules associated with this cache container’s configuration. Moreover, there were also additional changes to attributes of various elements, originating from the use of Wildfly 23 as the underlying container. For example, the managed-executor-service and managed-scheduled-executor-service elements now recognize the new hung-task-termination-period attribute. See the Wildfly 23 full model reference for details.

Upgrade to Wildfly 22

The Keycloak server was upgraded to use Wildfly 22 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 22 server. For example, Infinispan is now 11.0.8.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically. However, here are the most important changes, which you may need if you made your own configuration changes:

Migrating to 12.0.2

Read-only attributes

There was added support for the read-only user attributes. This includes the user attributes, which are not supposed to be edited by the user or by the administrator when updating user with REST API or with the Keycloak user interfaces. It can be important especially if you use:

  • Custom user storage providers

  • Custom authenticators

  • Custom JavaScript authorization policies, which establish authorization based on some user attribute

  • X.509 authenticator with custom attribute for mapping the X.509 certificate to the user identity

  • Any other custom functionality, where some of the user attributes are used as the metadata for storing authentication/authorization/identity context rather than simple user profile information.

See the details in the Threat model mitigation chapter.

Valid Request URIs

If you use the OpenID Connect parameter request_uri, a requirement exists that your client needs to have Valid Request URIs configured. This can be configured through the admin console on the client details page or through the admin REST API or client registration API. Valid Request URIs need to contain the list of Request URI values, which are permitted for the particular client. This is to avoid SSRF attacks. There is possibility to use wildcards or relative paths similarly such as the Valid Redirect URIs option, however for security purposes, we typically recommend to use as specific value as possible.

Migrating to 13.0.0

Upgrade to Wildfly 22

The Keycloak server was upgraded to use Wildfly 22 as the underlying container. This does not directly involve any specific Keycloak server functionality, but a few changes related to the migration, which are worth mentioning.

Dependency updates

The dependencies were updated to the versions used by Wildfly 22 server. For example, Infinispan is now 11.0.8.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically. If more detail is needed, because, for example, you did some configuration changes on your own, the list of the most important changes follows:

Migrating to 12.0.0

Upgrade to Wildfly 21

The Keycloak server was upgraded to use Wildfly 21 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 21 server. For example, Infinispan is now 11.0.4.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically. However, here are the most important changes, which you may need if you made your own configuration changes:

  • The object-memory element of Infinispan caches is now deprecated (unused) and is replaced with the heap-memory element.

Skip creation of user session for the Docker protocol authentication

No user session is created after successful authentication with the Docker protocol. For details, please refer to the Server Administration Guide.

Upgrade to PatternFly 4

The Keycloak login theme components have been upgraded to PatternFly 4. The old PatternFly 3 runs simultaneously with the new one, so it’s possible to keep PF3 components. However, some changes to the design of the login theme were performed. Please upgrade your custom login theme due them. An example with the necessary changes can be found in the keycloak/examples/themes/theme/sunrise directory. No additional setup is required.

Client Credentials Grant without refresh token by default

From this Keycloak version, the OAuth2 Client Credentials Grant endpoint does not issue refresh tokens by default. This behavior is aligned with the OAuth2 specification. As a side effect of this change, no user session is created on the Keycloak server side after successful Client Credentials authentication, which results in improved performance and memory consumption. Clients that use Client Credentials Grant are encouraged to stop using refresh tokens and instead always authenticate at every request with grant_type=client_credentials instead of using refresh_token as grant type. In relation to this, Keycloak has support for revocation of access tokens in the OAuth2 Revocation Endpoint, hence clients are allowed to revoke individual access tokens if needed.

For backwards compatibility, a possibility to stick to the behavior of old versions exists. When this is used, the refresh token will be still issued after a successful authentication with the Client Credentials Grant and also the user session will be created. This can be enabled for the particular client in the Keycloak admin console, in client details in the section with OpenID Connect Compatibility Modes with the switch Use Refresh Tokens For Client Credentials Grant.

Migrating to 11.0.0

Upgrade to Wildfly 20

The Keycloak server was upgraded to use Wildfly 20 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 20 server. For example, Infinispan is now 10.1.8.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically.

Cross-Datacenter Replication changes
  • You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as they are not tested anymore.

  • It is recommended to use the protocolVersion property added to the remote-store element when configuring Infinispan caches. When connecting to the Infinispan server 9.4.18, the recommended version of the hotrod protocol version is 2.9 as the Infinispan library version differs among Keycloak server and Infinispan server. For more details, see the Cross-Datacenter documentation.

  • It is recommended to use remoteStoreSecurityEnabled property under connectionsInfinispan subsystem. For more details, see the Cross-Datacenter documentation.

LDAP no-import bugfix

In the previous Keycloak version, when the LDAP provider was configured with Import Users OFF, it was possible to update the user even if some of non-LDAP mapped attributes were changed. This situation resulted in confusing behavior, when the attribute appeared to be updated, but it was not. In the current version, the update is not allowed to be performed at all if any non-LDAP mapped attributes are changed.

This should not affect most of the deployments, but some can be affected under some rare circumstances. For example if you previously tried to update a user with the admin REST API and the user had some incorrect attribute changes, the update was possible. With the current version, the update is not possible and you will be immediately informed about the reason.

UserModel changes

The fields username, email, firstName and lastName in the UserModel are migrated to custom attributes as a preparation for adding more sophisticated user profiles to Keycloak in an upcoming version. If a database contains users with custom attributes of that exact name, the custom attributes will need to be migrated before upgrading. This migration does not occur automatically. Otherwise, they will not be read from the database anymore and possibly deleted. This situation implies that the username can now also be accessed and set via UserModel.getFirstAttribute(UserModel.USERNAME). Similar implications exist for other fields. Implementers of SPIs subclassing the UserModel directly or indirectly should ensure that the behavior between setUsername and setSingleAttribute(UserModel.USERNAME, …​) (and similar for the other fields) is consistent. Users of the policy evaluation feature have to adapt their policies if they use the number of attributes in their evaluations since every user will now have four new attributes by default.

The public API of UserModel did not change. No changes to frontend resources or SPIs accessing user data are necessary. Also, the database did not change yet.

Instagram IdP migrated to new the API

Instagram IdP now uses new API as the old legacy API was deprecated. This requires getting new API credentials. For details, please refer to the Server Administration Guide.

Special attention is required for existing users that use Instagram IdP, specially the ones for whom it is the only authentication option. Such users have to log in to Keycloak using Instagram IdP before September 30th, 2020. After that day they’ll have to use a different authentication method (like password) to log in to manually update their Instagram social link, or create a new account in Keycloak. This is because Instagram user IDs are not compatible between the old and new API, however the new API temporarily returns both new and old user IDs to allow migration. Keycloak automatically migrates the ID once user logs in.

Non-standard token introspection endpoint removed

In previous versions, Keycloak advertised two introspection endpoints: token_introspection_endpoint and introspection_endpoint. The latter is the one defined by RFC-8414. The former, previously deprecated, has now been removed.

Migrating to 9.0.1

Legacy promise in JavaScript adapter

It is no longer necessary to set promiseType in the JavaScript adapter, and both are available at the same time. It is recommended to update applications to use native promise API (then and catch) as soon as possible, as the legacy API (success and error) will be removed at some point.

Duplicated top level groups

Version 9.0.1 fixes a problem which could create duplicated top level groups in the realm. Nevertheless the existence of previous duplicated groups makes the upgrade process fail. The Keycloak server can be affected by this issue if it is using an H2, MariaDB, MySQL or PostgreSQL database. Before launching the upgrade, check if the server contains duplicated top level groups. For example the following SQL query can be executed at database level to list them:

SELECT REALM_ID, NAME, COUNT(*) FROM KEYCLOAK_GROUP WHERE PARENT_GROUP is NULL GROUP BY REALM_ID, NAME HAVING COUNT(*) > 1;

Only one top level group can exist in each realm with the same name. Duplicates should be reviewed and deleted before the upgrade. The error in the upgrade contains the message Change Set META-INF/jpa-changelog-9.0.1.xml::9.0.1- KEYCLOAK-12579-add-not-null-constraint::keycloak failed.

Migrating to 9.0.0

Improved handling of user locale

A number of improvements have been made to how the locale for the login page is selected, as well as when the locale is updated for a user.

See the Server Administration Guide for more details.

Deprecated methods in token representation Java classes

In the year 2038 an int is no longer able to hold the value of seconds since 1970, as such we are working on updating these to long values. Moreover, another issue related with processing of int values exists in token representation. An int will by default result into 0 in the JSON representation, while it should not be included.

See JavaDocs for further details on exact methods that have been deprecated and replacement methods.

Migrating to 8.0.2

More authentication flows changes

REQUIRED and ALTERNATIVE executions not supported at same flow

In previous version, it was possible to have REQUIRED and ALTERNATIVE executions in the same authentication flow at the same level. There were some issues with this approach and we did the refactoring in the Authentication SPI, which means that this is not considered valid anymore. If ALTERNATIVE and REQUIRED executions are configured at the same level, the ALTERNATIVE executions are considered disabled. So when migrating to the newest version, your existing authentication flows will be automatically migrated preserved the same behavior as existed in the previous version. If they contain ALTERNATIVE executions at the same level as some REQUIRED executions, then the ALTERNATIVE executions will be added to the separate REQUIRED subflow. This should ensure same/similar behavior of the particular authentication flow as in the previous version. We always recommend to double-check the configuration of your authentication flow and test it to double-check that everything works as expected. This recommendation is true in particular if you have some more customized authentication flows with custom authenticator implementations.

Migrating to 8.0.0

New default Hostname provider

The old request and fixed hostname providers are replaced with a new default hostname provider. The request and fixed hostname providers are now deprecated and it is recommended to switch to the default hostname provider as soon as possible.

Upgrade to Wildfly 18

The Keycloak server was upgraded to use Wildfly 18 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 18 server. For example, Infinispan is now 9.4.16.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically.

Cross-Datacenter Replication changes
  • You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don’t test it anymore.

Deploying scripts to the server

Until now, administrators were allowed to upload scripts to the server through the Keycloak Administration Console as well as through the RESTful Admin API.

For now on, this capability is disabled by default and users should prefer to deploy scripts directly to the server. For more details, please take a look at JavaScript Providers.

Client credentials in the JavaScript adapter

In the previous releases, developers were allowed to provide client credentials to the JavaScript adapter. For now on, this capability was removed, because client-side apps are not safe to keep secrets.

Authentication flows changes

We did some refactoring and improvements related to the authentication flows, which requires some attention during migration.

OPTIONAL execution requirement removed

Regarding migration, the most important change is removing the support for the OPTIONAL requirement from authentication executions and replacing it with the CONDITIONAL requirement, which allows more flexibility. The existing OPTIONAL authenticators configured in the previous version are replaced with the CONDITIONAL subflows. These subflows have the Condition - User Configured condition configured as first execution, and the previously OPTIONAL authenticator (for example OTP Form) as second execution. From the user’s point of view, the behavior during authentication is the same as in the previous version.

Changes in the Java SPI

Some changes exist in the Java Authentication SPI and Credential Provider SPI. The interface Authenticator is not changed, but you may be affected if you’re developing more advanced authenticators, which introduce some new credential types (subclasses of CredentialModel). There are changes on the CredentialProvider interface and introduction of some new interfaces like CredentialValidator. Also you may be affected if your authenticator supported the OPTIONAL execution requirement. It is recommended to double-check the latest authentication examples in the server development guide for more details.

Freemarker template changes

Some changes in the freemarker templates exist. You may be affected if you have your own theme with custom freemarker templates for login forms or some account forms, especially for the forms related to OTP. It is recommended to double-check changes in the Freemarker templates in the latest Keycloak and align your templates according to it.

User credentials changes

We added more flexibility around storing of user credentials. Among other things, every user can have multiple credentials of the same type, for example multiple OTP credentials. As a result, some changes to the database schema were performed. However the credentials from the previous version should be automatically updated to the new format and users should be still able to login with their passwords or OTP credentials set in the previous version.

Migrating to 7.0.0

Upgrade to Wildfly 17

The Keycloak server was upgraded to use Wildfly 17 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 17 server. For example, Infinispan is now 9.4.14.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically.

Cross-Datacenter Replication changes
  • You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don’t test it anymore.

Migrating to 6.0.0

Upgrade to Wildfly 16

The Keycloak server was upgraded to use Wildfly 16 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 16 server. For example, Infinispan is now 9.4.8.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically.

Cross-Datacenter Replication changes
  • You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don’t test it anymore.

New optional client scope

We have added a new microprofile-jwt optional client scope to handle the claims defined in the MicroProfile/JWT Auth Specification. This new client scope defines protocol mappers to set the username of the authenticated user to the upn claim and to set the realm roles to the groups claim.

Ability to propagate prompt=none to default IDP

We have added a new switch in the OIDC identity provider configuration named Accepts prompt=none forward from client to identify IDPs that are able to handle forwarded requests that include the prompt=none query parameter.

Until now, when receiving an auth request with prompt=none a realm would return a login_required error if the user is not authenticated in the realm without checking if the user has been authenticated by an IDP. From now on, if a default IDP can be determined for the auth request (either by the use of the kc_idp_hint query param or by setting up a default IDP for the realm) and if the Accepts prompt=none forward from client switch has been enabled for the IDP, the auth request is forwarded to the IDP to check if the user has been authenticated there.

It is important to note that this switch is only taken into account if a default IDP is specified, in which case we know where to forward the auth request without having to prompt the user to select an IDP. If a default IDP cannot be determined we cannot assume which one will be used to fulfill the auth request so the request forwarding is not performed.

Migrating to 5.0.0

Upgrade to Wildfly 15

The Keycloak server was upgraded to use Wildfly 15 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 15 server. For example, Infinispan is now 9.4.3.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically.

Cross-Datacenter Replication changes
  • You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don’t test it anymore.

Migrating to 4.8.2

Google Identity Provider updated to use Google Sign-in authentication system

The Google Identity Provider implementation in Keycloak up to version 4.8.1 relies on the Google+ API endpoints for authorization and obtaining the user profile. From March 2019 onwards, Google is removing support for the Google+ API in favor of the new Google Sign-in authentication system. The Keycloak identity provider has been updated to use the new endpoints so if this integration is in use make sure you upgrade to Keycloak version 4.8.2 or later.

If you run into an error saying that the application identifier was not found in the directory, you will have to register the client application again in the Google API Console portal to obtain a new application id and secret.

It is possible that you will need to adjust custom mappers for non-standard claims that were provided by Google+ user information endpoint and are provided under different name by Google Sign-in API. Please consult Google documentation for the most up-to-date information on available claims.

LinkedIn social broker updated to Version 2 of LinkedIn APIs

Accordingly with LinkedIn, all developers need to migrate to version 2.0 of their APIs and OAuth 2.0. As such, we have updated our LinkedIn Social Broker.

Existing deployments using this broker may start experiencing errors when fetching user’s profile using version 2 of LinkedIn APIs. This error may be related with the lack of permissions granted to the client application used to configure the broker which may not be authorized to access the Profile API or request specific OAuth2 scopes during the authentication process.

Even for newly created LinkedIn client applications, you need to make sure that the client is able to request the r_liteprofile and r_emailaddress OAuth2 scopes, at least, as well that the client application can fetch current member’s profile from the https://api.linkedin.com/v2/me endpoint.

Due to these privacy restrictions imposed by LinkedIn in regards to access to member’s information and the limited set of claims returned by the current member’s Profile API, the LinkedIn Social Broker is now using the member’s email address as the default username. That means that the r_emailaddress is always set when sending authorization requests during the authentication.

Migrating to 4.6.0

New default client scopes

We have added new realm default client scopes roles and web-origins. These client scopes contain protocol mappers to add the roles of the user and allowed web origins to the token. During migration, these client scopes should be automatically added to all the OpenID Connect clients as default client scopes. Hence no setup should be required after database migration is finished.

Protocol mapper SPI addition

Related to this, a small addition to the (unsupported) Protocol Mappers SPI exists. You can be affected only if you implemented a custom ProtocolMapper. A new getPriority() method on the ProtocolMapper interface got introduced. The method has the default implementation set to return 0. If your protocol mapper implementation relies on the roles in the access token realmAccess or resourceAccess properties, you may need to increase the priority of your mapper.

Audience resolving

Audiences of all the clients, for which authenticated user has at least one client role in the token, are automatically added to the aud claim in the access token now. On the other hand, an access token may not automatically contain the audience of the frontend client, for which it was issued. Read the Server Administration Guide for more details.

JavaScript adapter promise

To use native JavaScript promise with the JavaScript adapter it is now required to set promiseType to native in the init options.

In the past if native promise was available a wrapper was returned that provided both the legacy Keycloak promise and the native promise. This was causing issues as the error handler was not always set prior to the native error event, which resulted in Uncaught (in promise) error.

Microsoft Identity Provider updated to use the Microsoft Graph API

The Microsoft Identity Provider implementation in Keycloak up to version 4.5.0 relies on the Live SDK endpoints for authorization and obtaining the user profile. From November 2018 onwards, Microsoft is removing support for the Live SDK API in favor of the new Microsoft Graph API. The Keycloak identity provider has been updated to use the new endpoints so if this integration is in use make sure you upgrade to Keycloak version 4.6.0 or later.

Legacy client applications registered under "Live SDK applications" won’t work with the Microsoft Graph endpoints due to changes in the id format of the applications. If you run into an error saying that the application identifier was not found in the directory, you will have to register the client application again in the Microsoft Application Registration portal to obtain a new application id.

Upgrade to Wildfly 14

The Keycloak server was upgraded to use Wildfly 14 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 14 server. For example, Infinispan is now 9.3.1.Final.

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically.

Cross-Datacenter Replication changes
  • You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don’t test it anymore.

Migrating to 4.4.0

Upgrade to Wildfly 13

The Keycloak server was upgraded to use Wildfly 13 as the underlying container. This does not directly involve any specific Keycloak server functionality, however, note these changes related to migration:

Dependency updates

The dependencies were updated to the versions used by the Wildfly 13 server. For example, Infinispan is now 9.2.4.Final and Undertow is 2.0.9.Final

Configuration changes

A few configuration changes exist in the standalone(-ha).xml and domain.xml files. You should follow the Downloading the Keycloak server section to handle the migration of configuration files automatically. However, here are the most important changes, which you may need if you made your own configuration changes:

  • Element eviction on infinispan caches is now deprecated (unused) and is replaced with element object-memory

  • The cache-container element in Infinispan subsystem does not recognize the jndi-attribute anymore.

Cross-Datacenter Replication changes
  • You will need to upgrade Infinispan server to version 9.4.19. The older version may still work, but it is not guaranteed as we don’t test it anymore.

  • You don’t need to configure security anymore in the Infinispan server configuration file.

  • The transaction element needs to be removed from the configuration of replicated caches in the Infinispan server configuration file. This is needed because of the infinispan bug https://issues.redhat.com/browse/ISPN-9323.

Migration to 4.3.0

Hostname configuration

In previous versions it was recommended to use a filter to specify permitted hostnames. It is now possible to set a fixed hostname which makes it easier to make sure the valid hostname is used and also allows internal applications to invoke Keycloak through an alternative URL, for example an internal IP address. It is recommended that you switch to this approach in production.

Migrating to 4.0.0

Client Templates changed to Client Scopes

We added support for Client Scopes, which requires some attention during migration.

Client Templates changed to Client Scopes

Client Templates were changed to Client Scopes. If you had any Client Templates, their protocol mappers and role scope mappings will be preserved.

Spaces replaced in the names

Client templates with the space character in the name were renamed by replacing spaces with an underscore, because spaces are not allowed in the name of client scopes. For example, a client template my template will be changed to client scope my_template.

Linking Client Scopes to Clients

For clients which had the client template, the corresponding client scope is now added as Default Client Scope to the client. So protocol mappers and role scope mappings will be preserved on the client.

Realm Default Client Scopes not linked with existing clients

During the migration, the list of built-in client scopes is added to each realm as well as list of Realm Default Client Scopes. However, existing clients are NOT upgraded and new client scopes are NOT automatically added to them. Also all the protocol mappers and role scope mappings are kept on existing clients. In the new version, when you create a new client, it automatically has Realm Default Client Scopes attached to it and it does not have any protocol mappers attached to it. We did not change existing clients during migration as it would be impossible to properly detect customizations, which you will have for protocol mappers of the clients, for example. If you want to update existing clients (remove protocol mappers from them and link them with client scopes), you will need to do it manually.

Consents need to be confirmed again

The client scopes change required the refactoring of consents. Consents now point to client scopes, not to roles or protocol mappers. Because of this change, the previously confirmed persistent consents by users are not valid anymore and users need to confirm the consent page again after the migration.

Some configuration switches removed

The switch Scope Param Required was removed from Role Detail. The switches Consent Required and Consent Text were removed from the Protocol Mapper details. Those switches are replaced with the Client Scope feature.

Changes to Authorization Services

We added support for UMA 2.0. This version of the UMA specification introduced some important changes on how permissions are obtained from the server.

Here are the main changes introduced by UMA 2.0 support. See Authorization Services Guide for details.

Authorization API was removed

Prior to UMA 2.0 (UMA 1.0), client applications were using the Authorization API to obtain permissions from the server in the format of an RPT. The new version of UMA specification has removed the Authorization API which was also removed from Keycloak. In UMA 2.0, RPTs can now be obtained from the token endpoint by using a specific grant type. See Authorization Services Guide for details.

Entitlement API was removed

With the introduction of UMA 2.0, we decided to leverage the token endpoint and UMA grant type to allow obtaining RPTs from Keycloak and avoid having different APIs. The functionality provided by the Entitlement API was kept the same and is still possible to obtain permissions for a set of one or more resources and scopes or all permissions from the server in case no resource or scope is provided. See Authorization Services Guide for details.

Changes to UMA Discovery Endpoint

UMA Discovery document changed, see Authorization Services Guide for details.

Changes to Keycloak Authorization JavaScript adapter

The Keycloak Authorization JavaScript adapter (keycloak-authz.js) changed in order to comply with the changes introduced by UMA 2.0 while keeping the same behavior as before. The main change is on how you invoke both authorization and entitlement methods which now expect a specific object type representing an authorization request. This new object type provides more flexibility on how permissions can be obtained from the server by supporting the different parameters supported by the UMA grant type. See Authorization Services Guide for details.

One of the main changes introduced by this release is that you are no longer required to exchange access tokens with RPTs in
order to access resources protected by a resource server (when not using UMA). Depending on how the policy enforcer is configured on the resource server side, you can just send regular
access tokens as a bearer token and permissions will still be enforced.
Changes to Keycloak Authorization Client Java API

When upgrading to the new version of Keycloak Authorization Client Java API, you’ll notice that some representation classes were moved to a different package in org.keycloak:keycloak-core.

Migrating to 3.4.2

Added session_state parameter to OpenID Connect Authentication Response

The OpenID Connect Session Management specification requires that the parameter session_state is present in the OpenID Connect Authentication Response.

In past releases, we did not have this parameter, but now Keycloak adds this parameter by default, as required by the specification.

However, some OpenID Connect / OAuth2 adapters, and especially older Keycloak adapters, may have issues with this new parameter.

For example, the parameter will be always present in the browser URL after successful authentication to the client application. In these cases, it may be useful to disable adding the session_state parameter to the authentication response. This can be done for the particular client in the Keycloak admin console, in client details in the section with OpenID Connect Compatibility Modes, described in Compatibility with older adapters. Dedicated Exclude Session State From Authentication Response switch exists, which can be turned on to prevent adding the session_state parameter to the Authentication Response.

The parameter session_state was added in 3.4.2, however the switch Exclude Session State From Authentication Response was added in 4.0.0.Beta1. If your Keycloak server is on 3.4.2 or 3.4.3 and you have issues with session_state parameter, you will need to upgrade the server to 4.0.0.Beta1 or newer.

Migrating to 3.2.0

New password hashing algorithms

We’ve added two new password hashing algorithms (pbkdf2-sha256 and pbkdf2-sha512). New realms will use the pbkdf2-sha256 hashing algorithm with 27500 hashing iterations. Since pbkdf2-sha256 is slightly faster than pbkdf2 the iterations was increased to 27500 from 20000.

Existing realms are upgraded if the password policy contains the default value for hashing algorithm (not specified) and iteration (20000). If you have changed the hashing iterations you need to manually change to pbkdf2-sha256 if you’d like to use the more secure hashing algorithm.

ID Token requires scope=openid

OpenID Connect specification requires that parameter scope with value openid is used in initial authorization request. So in Keycloak 2.1.0 we changed our adapters to use scope=openid in the redirect URI to Keycloak. Now we changed the server part too and ID token will be sent to the application just if scope=openid is really used. If it’s not used, then ID token will be skipped and just Access token and Refresh token will be sent to the application. This also allows that you can omit the generation of ID Token on purpose - for example for space or performance purposes.

Direct grants (OAuth2 Resource Owner Password Credentials Grant) and Service accounts login (OAuth2 Client credentials grant) also don’t use ID Token by default now. You need to explicitly add scope=openid parameter to have ID Token included.

Authentication sessions and Action tokens

We are working on support for multiple datacenters. As the initial step, we introduced authentication session and action tokens. Authentication session replaces Client session, which was used in previous versions. Action tokens are currently used especially for the scenarios, where the authenticator or requiredActionProvider requires sending email to the user and requires user to click on the link in email.

Here are concrete changes related to this, which may affect you for the migration.

First change related to this is introducing new Infinispan caches authenticationSessions and actionTokens in standalone.xml or standalone-ha.xml. If you use our migration CLI, you don’t need to care much as your standalone(-ha).xml files will be migrated automatically.

Second change is changing of some signatures in methods of authentication SPI. This may affect you if you use custom Authenticator or RequiredActionProvider. Classes AuthenticationFlowContext and RequiredActionContext now allow to retrieve authentication session instead of client session.

We also added some initial support for sticky sessions. You may want to change your load balancer/proxy server and configure it if you don’t want to suffer from it and want to have better performance. The route is added to the new AUTH_SESSION_ID cookie. More info in the clustering documentation.

Another change is, that token.getClientSession() was removed. This may affect you for example if you’re using Client Initiated Identity Broker Linking feature.

The ScriptBasedAuthenticator changed the binding name from clientSession to authenticationSession, so you would need to update your scripts if you’re using this authenticator.

Finally we added some new timeouts to the admin console. This allows you for example to specify different timeouts for the email actions triggered by admin and by user himself.

Migrating to 2.5.1

Migration of old offline tokens

If you migrate from version 2.2.0 or older and you used offline tokens, then your offline tokens didn’t have KID in the token header. We added KID to the token header in 2.3.0 together with the ability to have multiple realm keys, so Keycloak is able to find the correct key based on the token KID.

For the offline tokens without KID, Keycloak 2.5.1 will always use the active realm key to find the proper key for the token verification. In other words, migration of old offline tokens will work. So for example, your user requested offline token in 1.9.8, then you migrate from 1.9.8 to 2.5.1 and then your user will be still able to refresh his old offline token in 2.5.1 version.

But a limitation exists. Once you change the realm active key, the users won’t be able to refresh old offline tokens anymore. So you shouldn’t change the active realm key until all your users with offline tokens refreshed their tokens. Obviously newly refreshed tokens will have KID in the header, so after all users exchange their old offline tokens, you are free to change the active realm key.

Migrating to 2.5.0

Changes to the Infinispan caches

The realms cache defined in the infinispan subsystem in standalone.xml or standalone-ha.xml configuration file, now has the eviction with the 10000 records by default. This is the same default as the users cache.

Also the authorization cache now doesn’t have any eviction on it by default.

Migrating to 2.4.0

Server SPI split into Server SPI and Sever SPI Private

The keycloak-server-spi module has been split into keycloak-server-spi and keycloak-server-spi-private. APIs within keycloak-server-spi will not change between minor releases, while we reserve the right and may quite likely change APIs in keycloak-server-spi-private between minor releases.

Key encryption algorithm in SAML assertions

Key in SAML assertions and documents are now encrypted using RSA-OAEP encryption scheme. If you want to use encrypted assertions, make sure that service providers understand this encryption scheme. In the unlikely case that SP would not be able to handle the new scheme, Keycloak can be made to use legacy RSA-v1.5 encryption scheme when started with system property keycloak.saml.key_trans.rsa_v1.5 set to true.

Infinispan caches realms and users are always local

Even if you use Keycloak in cluster, the caches realms and users defined in infinispan subsystem in standalone-ha.xml are always local caches now. A separate cache work exists, which handles sending invalidation messages between cluster nodes and informing whole cluster what records in underlying realms and users caches should be invalidated.

Migrating to 2.3.0

Default max results on paginated endpoints

All Admin REST API endpoints that support pagination now have a default max results set to 100. If you want to return more than 100 entries you need to explicitly specify that with ?max=<RESULTS>.

In 2.3.0 release we added support for Public Key Rotation. When admin rotates the realm keys in Keycloak admin console, the Client Adapter will be able to recognize it and automatically download new public key from Keycloak. However this automatic download of new keys is done just if you don’t have realm-public-key option in your adapter with the hardcoded public key. For this reason, we don’t recommend to use realm-public-key option in adapter configuration anymore.

Note this option is still supported, but it may be useful just if you really want to have hardcoded public key in your adapter configuration and never download the public key from Keycloak. In theory, one reason for this can be to avoid man-in-the-middle attack if you have untrusted network between adapter and Keycloak, however in that case, it is much better option to use HTTPS, which will secure all the requests between adapter and Keycloak.

Added Infinispan cache keys

In this release, we added new cache keys to the infinispan subsystem, which is defined in standalone.xml or standalone-ha.xml configuration file. It has also some eviction and expiration defined. This cache is internally used for caching the external public keys of the entities trusted by the server (Identity providers or clients, which uses authentication with signed JWT).

Migrating to 2.2.0

databaseSchema property deprecated

The databaseSchema property for both JPA and Mongo is now deprecated and is replaced with initializeEmpty and migrationStrategy. initializeEmpty can bet set to true or false and controls if an empty database should be initialized. migrationStrategy can be set to update, validate and manual. manual is only supported for relational databases and will write an SQL file with the required changes to the database schema. Please note that for Oracle database, the created SQL file contains SET DEFINE OFF command understood by Oracle SQL clients. Should the script be consumed by any other client, please replace the lines with equivalent command of the tool of your choice that disables variable expansion or remove it completely if such functionality is not applicable.

Changes in Client’s Valid Redirect URIs

The following scenarios are affected:

  • When a Valid Redirect URI with query component is saved in a Client (e.g. http://localhost/auth?foo=bar), redirect_uri in authorization request must exactly match this URI (or other registered URI in this Client).

  • When a Valid Redirect URI without a query component is saved in a Client, redirect_uri must exactly match as well.

  • Wildcards in registered Valid Redirect URIs are no longer supported when query component is present in this URI, so the redirect_uri needs to exactly match this saved URI as well.

  • Fragments in registered Valid Redirect URIs (like http://localhost/auth#fragment) are no longer allowed.

Authenticate by default removed from Identity Providers

Identity providers no longer has an option to set it as a default authentication provider. Instead go to Authentication, select the Browser flow and configure the Identity Provider Redirector. It has an option to set the default identity provider.

Migrating to 2.0.0

Upgrading from 1.0.0.Final no longer supported

Upgrading from 1.0.0.Final is no longer supported. To upgrade to this version upgrade to 1.9.8.Final prior to upgrading to 2.0.0.

Migrating to 1.9.5

Default password hashing interval increased to 20K

The default password hashing interval for new realms has been increased to 20K (from 1 previously). This change will have an impact on performance when users authenticate. For example with the old default (1) it takes less than 1 ms to hash a password, but with the new default (20K) the same operation can take 50-100 ms.

Migrating to 1.9.3

Add User script renamed

The script to add admin users to Keycloak has been renamed to add-user-keycloak.

Migrating to 1.9.2

Adapter option auth-server-url-for-backend-requests removed

We’ve removed the option auth-server-url-for-backend-requests due to issues in some scenarios when it was used. In more details, it was possible to access the Keycloak server from 2 different contexts (internal and external), which was causing issues in token validations etc.

If you still want to use the optimization of network, which this option provided (avoid the application to send backchannel requests through load balancer but send them to local Keycloak server directly) you may need to handle it at hosts configuration (DNS) level.

Migrating to 1.9.0

Themes and providers directory moved

We’ve moved the themes and providers directories from standalone/configuration/themes and standalone/configuration/providers to themes and providers respectively. If you have added custom themes and providers you need to move them to the new location. You also need to update keycloak-server.json as it’s changed due to this.

Adapter subsystems only bring in dependencies if Keycloak is on

Previously, if you had installed our SAML or OIDC Keycloak subsystem adapters into WildFly or JBoss EAP, we would automatically include Keycloak client jars into EVERY application regardless if you were using Keycloak or not. These libraries are now only added to your deployment if you have Keycloak authentication turned on for that adapter (via the subsystem, or auth-method in web.xml)

Client Registration service endpoints moved

The Client Registration service endpoints have been moved from {realm-name}/clients to {realm-name}/clients-registrations.

Session state parameter in authentication response renamed

In the OpenID Connect authentication response we used to return the session state as session-state this is not correct according to the specification and has been renamed to session_state.

Deprecated OpenID Connect endpoints

In 1.2 we deprecated a number of endpoints that where not consistent with the OpenID Connect specifications, these have now been removed. This also applies to the validate token endpoint that is replaced with the new introspect endpoint in 1.8.

Updates to theme templates

Feedback in template.ftl has been moved and format has changed slightly.

Module and source code reorganization

Most of our modules and source code have been consolidated into two maven modules: keycloak-server-spi and keycloak-services. SPI interfaces are in server-spi, implementations are in keycloak-services. All JPA dependent modules have been consolidated under keycloak-model-jpa. Same goes with mongo and Infinispan under modules keycloak-model-mongo and keycloak-model-infinispan.

For adapters, session id changed after login

To plug a security attack vector, for platforms that support it (Tomcat 8, Undertow/WildFly), the Keycloak OIDC and SAML adapters will change the session id after login. You can turn off this behavior check adapter config switches.

SAML SP Client adapter changes

Keycloak SAML SP Client adapter now requires a specific endpoint, /saml to be registered with your IDP.

Migrating to 1.8.0

Admin account

In previous releases we shipped with a default admin user with a default password, this has now been removed. If you are doing a new installation of 1.8 you will have to create an admin user as a first step.

OAuth2 token introspection

In order to add more compliance with OAuth2 specification, we added a new endpoint for token introspection. The new endpoint can reached at /realms/{realm-name}/protocols/openid-connect/token/introspect and it is solely based on RFC-7662.

The /realms/{realm-name}/protocols/openid-connect/validate endpoint is now deprecated and we strongly recommend you to move to the new introspection endpoint as soon as possible. The reason for this change is that RFC-7662 provides a more standard and secure introspection endpoint.

The new token introspection URL can now be obtained from OpenID Connect Provider’s configuration at /realms/{realm-name}/.well-known/openid-configuration. There you will find a claim with name token_introspection_endpoint within the response. Only confidential clients are allowed to invoke the new endpoint, where these clients will be usually acting as a resource server and looking for token metadata in order to perform local authorization checks.

Migrating to 1.7.0.CR1

Direct access grants disabled by default for clients

In order to add more compliance with OpenID Connect specification, we added flags into admin console to Client Settings page, where you can enable/disable various kinds of OpenID Connect/OAuth2 flows (Standard flow, Implicit flow, Direct Access Grants, Service Accounts). As part of this, we have Direct Access Grants (corresponds to OAuth2 Resource Owner Password Credentials Grant) disabled by default for new clients.

Clients migrated from previous version have Direct Access Grants enabled just if they had flag Direct Grants Only on. The Direct Grants Only flag was removed as if you enable Direct Access Grants and disable both Standard+Implicit flow, you will achieve same effect.

We also added built-in client admin-cli to each realm. This client has Direct Access Grants enabled. So if you’re using Admin REST API or Keycloak admin-client, you should update your configuration to use admin-cli instead of security-admin-console as the latter one doesn’t have direct access grants enabled anymore by default.

Option 'Update Profile On First Login' moved from Identity provider to Review Profile authenticator

In this version, we added First Broker Login, which allows you to specify what exactly should be done when new user is logged through Identity provider (or Social provider), but no Keycloak user linked to the social account exists yet. As part of this work, we added option First Login Flow to identity providers where you can specify the flow and then you can configure this flow under Authentication tab in admin console.

We also removed the option Update Profile On First Login from the Identity provider settings and moved it to the configuration of Review Profile authenticator. So once you specify which flow should be used for your Identity provider (by default it’s First Broker Login flow), you go to Authentication tab, select the flow and then you configure the option under Review Profile authenticator.

Element 'form-error-page' in web.xml not supported anymore

form-error-page in web.xml will no longer work for client adapter authentication errors. You must define an error-page for the various HTTP error codes. See documentation for more details if you want to catch and handle adapter error conditions.

IdentityProviderMapper changes

The interface itself and method signatures did not change. However some changes in the behavior exist. We added First Broker Login flow in this release and the method IdentityProviderMapper.importNewUser is now called after First Broker Login flow is finished. So if you want to have any attribute available in Review Profile page, you would need to use the method preprocessFederatedIdentity instead of importNewUser . You can set any attribute by invoke BrokeredIdentityContext.setUserAttribute and that will be available on Review profile page.

Migrating to 1.6.0.Final

Option that refresh tokens are not reusable anymore

Old versions of Keycloak allowed reusing refresh tokens multiple times. Keycloak still permits this, but also have an option Revoke refresh token to disallow it. Option is under token settings in admin console. When a refresh token is used to obtain a new access token a new refresh token is also included. When option is enabled, then this new refresh token should be used next time the access token is refreshed. It won’t be possible to reuse old refresh token multiple times.

Some packages renamed

We did a bit of restructure and renamed some packages. It is mainly about renaming internal packages of util classes. The most important classes used in your application ( for example AccessToken or KeycloakSecurityContext ) as well as the SPI are still unchanged. However, a slight chance exists that you will be affected and will need to update imports of your classes. For example if you are using multitenancy and KeycloakConfigResolver, you will be affected as for example class HttpFacade was moved to different package - it is org.keycloak.adapters.spi.HttpFacade now.

Persisting user sessions

We added support for offline tokens in this release, which means that we are persisting "offline" user sessions into database now. If you are not using offline tokens, nothing will be persisted for you, so you don’t need to care about worse performance for more DB writes. However in all cases, you will need to update standalone/configuration/keycloak-server.json and add userSessionPersister like this:

"userSessionPersister": {
    "provider": "jpa"
},

If you want sessions to be persisted in Mongo instead of classic RDBMS, use provider mongo instead.

Migrating to 1.5.0.Final

Realm and User cache providers

Infinispan is now the default and only realm and user cache providers. In non-clustered mode a local Infinispan cache is used. We’ve also removed our custom in-memory cache and the no cache providers. If you have realmCache or userCache set in keycloak-server.json to mem or none please remove these. As Infinispan is the only provider the realmCache and userCache objects are no longer needed and can be removed.

Uses Session providers

Infinispan is now the default and only user session provider. In non-clustered mode a local Infinispan cache is used. We’ve also removed the JPA and Mongo user session providers. If you have userSession set in keycloak-server.json to mem, jpa or mongo please remove it. As Infinispan is the only provider the userSession object is no longer needed and can be removed.

For anyone that wants to achieve increased durability of user sessions this can be achieved by configuring the user session cache with more than one owner or use a replicated cache. It’s also possible to configure Infinispan to persist caches, although that would have impacts on performance.

Contact details removed from registration and account management

In the default theme we have now removed the contact details from the registration page and account management. The admin console now lists all the users attributes, not just contact specific attributes. The admin console also has the ability to add/remove attributes to a user. If you want to add contact details, please refer to the address theme included in the examples.

Migrating to 1.3.0.Final

Direct Grant API always enabled

In the past Direct Grant API (or Resource Owner Password Credentials) was disabled by default and an option to enable it on a realm existed. The Direct Grant API is now always enabled and the option to enable/disable for a realm is removed.

Database changed

There are again few database changes. Remember to back up your database prior to upgrading.

UserFederationProvider changed

There are few minor changes in UserFederationProvider interface. You may need to sync your implementation when upgrade to newer version and upgrade few methods, which has changed signature. Changes are really minor, but were needed to improve performance of federation.

WildFly 9.0.0.Final

Following on from the distribution changes that was done in the last release the standalone download of Keycloak is now based on WildFly 9.0.0.Final. This also affects the overlay which can only be deployed to WildFly 9.0.0.Final or JBoss EAP 6.4.0.GA. WildFly 8.2.0.Final is no longer supported for the server.

WildFly, JBoss EAP and JBoss AS7 adapters

There are now 3 separate adapter downloads for WildFly, JBoss EAP and JBoss AS7:

  • eap6

  • wf9

  • wf8

  • as7

Make sure you grab the correct one.

You also need to update standalone.xml as the extension module and subsystem definition has changed. See Securing Applications and Services Guide for details.

Migrating from 1.2.0.Beta1 to 1.2.0.RC1

Distribution changes

Keycloak is now available in 3 downloads: standalone, overlay and demo bundle. The standalone is intended for production and non-JEE developers. Overlay is aimed at adding Keycloak to an existing WildFly 8.2 or EAP 6.4 installation and is mainly for development. Finally we have a demo (or dev) bundle that is aimed at developers getting started with Keycloak. This bundle contains a WildFly server, with Keycloak server and adapter included. It also contains all documentation and examples.

Database changed

This release contains again a number of changes to the database. The biggest one is Application and OAuth client merge. Remember to back up your database prior to upgrading.

Application and OAuth client merge

Application and OAuth clients are now merged into Clients. The UI of admin console is updated and database as well. Your data from database should be automatically updated. The previously set Applications will be converted into Clients with Consent required switch off and OAuth Clients will be converted into Clients with this switch on.

Migrating from 1.1.0.Final to 1.2.0.Beta1

Database changed

This release contains a number of changes to the database. Remember to back up your database prior to upgrading.

iss in access and id tokens

The value of iss claim in access and id tokens have changed from realm name to realm url. This is required by OpenID Connect specification. If you’re using our adapters no change is required, except if you’ve been using bearer-only without specifying the auth-server-url, you have to add it now. If you’re using another library (or RSATokenVerifier) you need to make the corresponding changes when verifying iss.

OpenID Connect endpoints

To comply with OpenID Connect specification the authentication and token endpoints have been changed to having a single authentication endpoint and a single token endpoint. As per-spec response_type and grant_type parameters are used to select the required flow. The old endpoints (/realms/{realm-name}/protocols/openid-connect/login, /realms/{realm-name}/protocols/openid-connect/grants/access, /realms/{realm-name}/protocols/openid-connect/refresh, /realms/{realm-name}/protocols/openid-connect/access/codes) are now deprecated and will be removed in a future version.

Theme changes

The layout of themes has changed. The directory hierarchy used to be type/name this is now changed to name/type. For example a login theme named sunrise used to be deployed to standalone/configuration/themes/login/sunrise, which is now moved to standalone/configuration/themes/sunrise/login. This change was done to make it easier to have groups of the different types for the same theme into one folder.

If you deployed themes as a JAR in the past you had to create a custom theme loader which required Java code. This has been simplified to only requiring a plain text file (META-INF/keycloak-themes.json) to describe the themes included in a JAR.

Claims changes

Previously a dedicated Claims tab existed in the admin console for application and OAuth clients. This was used to configure which attributes should go into access token for particular application/client. This was removed and is replaced with protocol mappers which are more flexible.

You don’t need to care about migration of database from previous version. We did migration scripts for both RDBMS and Mongo, which should ensure that claims configured for particular application/client will be converted into corresponding protocol mappers (Still it’s safer to back up DB before migrating to newer version though). Same applies for exported JSON representation from previous version.

Social migration to identity brokering

We refactored social providers SPI and replaced it with Identity Brokering SPI, which is more flexible. The Social tab in admin console is renamed to Identity Provider tab.

Again you don’t need to care about migration of database from previous version similarly like for Claims/protocol mappers. Both configuration of social providers and "social links" to your users will be converted to corresponding Identity providers.

Only required action from you would be to change allowed Redirect URI in the admin console of particular 3rd party social providers. You can first go to the Keycloak admin console and copy Redirect URI from the page where you configure the identity provider. Then you can simply paste this as allowed Redirect URI to the admin console of 3rd party provider (IE. Facebook admin console).

Migrating from 1.1.0.Beta1 to 1.1.0.Beta2

  • adapters are now a separate download. They are not included in appliance and war distribution. We have too many now and the distro is getting bloated.

  • org.keycloak.adapters.tomcat7.KeycloakAuthenticatorValve +org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve

  • JavaScript adapter now has idToken and idTokenParsed properties. If you use idToken to retrieve first name, email, etc. you need to change this to idTokenParsed.

  • The as7-eap-subsystem and keycloak-wildfly-subsystem have been merged into one keycloak-subsystem. If you have an existing standalone.xml or domain.xml, you will need edit near the top of the file and change the extension module name to org.keycloak.keycloak-subsystem. For AS7 only, the extension module name is org.keycloak.keycloak-as7-subsystem.

  • Server installation is no longer supported on AS7. You can still use AS7 as an application client.

Migrating from 1.0.x.Final to 1.1.0.Beta1

  • RealmModel JPA and Mongo storage schema has changed

  • UserSessionModel JPA and Mongo storage schema has changed as these interfaces have been refactored

  • Upgrade your adapters, old adapters are not compatible with Keycloak 1.1. We interpreted JSON Web Token and OIDC ID Token specification incorrectly. 'aud' claim must be the client id, we were storing the realm name in there and validating it.

Migrating from 1.0 RC-1 to RC-2

  • A lot of info level logging has been changed to debug. Also, a realm no longer has the jboss-logging audit listener by default. If you want log output when users login, logout, change passwords, etc. enable the jboss-logging audit listener through the admin console.

Migrating from 1.0 Beta 4 to RC-1

  • logout REST API has been refactored. The GET request on the logout URI does not take a session_state parameter anymore. You must be logged in in order to log out the session. You can also POST to the logout REST URI. This action requires a valid refresh token to perform the logout. The signature is the same as refresh token minus the grant type form parameter. See documentation for details.

Migrating from 1.0 Beta 1 to Beta 4

  • LDAP/AD configuration is changed. It is no longer under the "Settings" page. It is now under Users→Federation. Add Provider will show you an "ldap" option.

  • Authentication SPI has been removed and rewritten. The new SPI is UserFederationProvider and is more flexible.

  • ssl-not-required +ssl-required +all +external +none

  • DB Schema has changed again.

  • Created applications now have a full scope by default. This means that you don’t have to configure the scope of an application if you don’t want to.

  • Format of JSON file for importing realm data was changed. Now role mappings is available under the JSON record of particular user.

Migrating from 1.0 Alpha 4 to Beta 1

  • DB Schema has changed. We have added export of the database to Beta 1, but not the ability to import the database from older versions. This will be supported in future releases.

  • For all clients except bearer-only applications, you must specify at least one redirect URI. Keycloak will not allow you to log in unless you have specified a valid redirect URI for that application.

  • Direct Grant API +ON

  • standalone/configuration/keycloak-server.json

  • JavaScript adapter

  • Session Timeout

Migrating from 1.0 Alpha 2 to Alpha 3

  • SkeletonKeyToken, SkeletonKeyScope, SkeletonKeyPrincipal, and SkeletonKeySession have been renamed to: AccessToken, AccessScope, KeycloakPrincipal, and KeycloakAuthenticatedSession respectively.

  • ServletOAuthClient.getBearerToken() method signature has changed. It now returns an AccessTokenResponse so that you can obtain a refresh token too.

  • adapters now check the access token expiration with every request. If the token is expired, they will attempt to invoke a refresh on the auth server using a saved refresh token.

  • Subject in AccessToken has been changed to the User ID.

Migrating from 1.0 Alpha 1 to Alpha 2

  • DB Schema has changed. We don’t have any data migration utilities yet as of Alpha 2.

  • JBoss and WildFly adapters are now installed via a WildFly subsystem. Please review the adapter installation documentation. Edits to standalone.xml are now required.

  • A new credential type "secret" got introduced. Unlike other credential types, it is stored in plain text in the database and can be viewed in the admin console.

  • Application and OAuth Client credentials are no longer required. These client types are now hard coded to use the "secret" credential type.

  • Because of the "secret" credential change to Application and OAuth Client, you’ll have to update your keycloak.json configuration files and regenerate a secret within the Application or OAuth Client credentials tab in the administration console.

Upgrading the Keycloak server

You upgrade the server before you upgrade the adapters.

Preparing for upgrading

Perform the following steps before you upgrade the server.

Procedure
  1. Shutdown Keycloak.

  2. Back up the old installation, such as configuration, themes, and so on.

  3. Handle any open transactions and delete the data/tx-object-store/ transaction directory.

  4. Back up the database using instructions in the documentation for your relational database.

    The database will no longer be compatible with the old server after you upgrade the server. If you need to revert the upgrade, first restore the old installation, and then restore the database from the backup copy.

After the upgrade of Keycloak, only if the feature persistent-user-sessions is enabled, users will still be logged in with their online sessions. If it is not enabled, users will have to log in again, except where offline user sessions are used.

Information about failed logins for the brute force detection and currently ongoing authentication flows is only stored in the internal caches that are cleared when Keycloak is shut down. Users currently authenticating, changing their passwords or resetting their password will need to restart the authentication flow once Keycloak is up and running again.

Downloading the Keycloak server

Once you have prepared for the upgrade, you can download the server.

Procedure
  1. Download and extract keycloak-25.0.6.zip from the Keycloak website.

    After extracting this file, you should have a directory that is named keycloak-25.0.6.

  2. Move this directory to the desired location.

  3. Copy conf/, providers/ and themes/ from the previous installation to the new installation.

Migrating the database

Keycloak can automatically migrate the database schema, or you can choose to do it manually. By default the database is automatically migrated when you start the new installation for the first time.

Automatic relational database migration

To perform an automatic migration, start the server connected to the desired database. If the database schema has changed for the new server version, the migration starts automatically unless the database has too many records.

For example, creating an index on tables with millions of records can be time-consuming and cause a major service disruption. Therefore, a threshold of 300000 records exists for automatic migration. If the number of records exceeds this threshold, the index is not created. Instead, you find a warning in the server logs with the SQL commands that you can apply manually.

To change the threshold, set the index-creation-threshold property, value for the default connections-liquibase provider:

kc.[sh|bat] start --spi-connections-liquibase-default-index-creation-threshold=300000

Manual relational database migration

To enable manual upgrading of the database schema, set the migration-strategy property value to "manual" for the default connections-jpa provider:

kc.[sh|bat] start --spi-connections-jpa-quarkus-migration-strategy=manual

When you start the server with this configuration, the server checks if the database needs to be migrated. The required changes are written to the bin/keycloak-database-update.sql SQL file that you can review and manually run against the database.

To change the path and name of the exported SQL file, set the migration-export property for the default connections-jpa provider:

kc.[sh|bat] start --spi-connections-jpa-quarkus-migration-export=<path>/<file.sql>

For further details on how to apply this file to the database, see the documentation for your relational database. After the changes have been written to the file, the server exits.

Migrating themes

If you created custom themes, those themes must be migrated to the new server. Also, any changes to the built-in themes might need to be reflected in your custom themes, depending on which aspects you customized.

Procedure
  1. Copy your custom themes from the old server themes directory to the new server themes directory.

  2. Use the following sections to migrate templates, messages, and styles.

    • If you customized any of the updated templates listed in Migration Changes, compare the template from the base theme to check for any changes you need to apply.

    • If you customized messages, you might need to change the key or value or to add additional messages.

    • If you customized any styles and you are extending the Keycloak themes, review the changes to the styles. If you are extending the base theme, you can skip this step.

Migrating templates

If you customized any template, review the new version to decide about updating your customized template. If you made minor changes, you could compare the updated template to your customized template. However, if you made many changes, consider comparing the new template to your customized template. This comparison will show you what changes you need to make.

You can use a diff tool to compare the templates. The following screenshot compares the info.ftl template from the Login theme and an example custom theme:

Updated version of a Login theme template versus a custom Login theme template

Updated version of a Login theme template versus a custom Login theme template

This comparison shows that the first change (Hello world!!) is a customization, while the second change (if pageRedirectUri) is a change to the base theme. By copying the second change to your custom template, you have successfully updated your customized template.

In an alternative approach, the following screenshot compares the info.ftl template from the old installation with the updated info.ftl template from the new installation:

Login theme template from the old installation versus the updated Login theme template

Login theme template from the old installation versus the updated Login theme template

This comparison shows what has been changed in the base template. You can then manually make the same changes to your modified template. Since this approach is more complex, use this approach only if the first approach is not feasible.

Migrating messages

If you added support for another language, you need to apply all the changes listed above. If you have not added support for another language, you might not need to change anything. You need to make changes only if you have changed an affected message in your theme.

Procedure
  1. For added values, review the value of the message in the base theme to determine if you need to customize that message.

  2. For renamed keys, rename the key in your custom theme.

  3. For changed values, check the value in the base theme to determine if you need to make changes to your custom theme.

Migrating styles

You might need to update your custom styles to reflect changes made to the styles from the built-in themes. Consider using a diff tool to compare the changes to stylesheets between the old server installation and the new server installation.

For example:

$ diff KEYCLOAK_HOME_OLD/themes/keycloak/login/resources/css/login.css \
KEYCLOAK_HOME_NEW/themes/keycloak/login/resources/css/login.css

Review the changes and determine if they affect your custom styling.

Upgrading Keycloak adapters

After you upgrade the Keycloak server, you can upgrade the adapters. Earlier versions of the adapter might work with later versions of the Keycloak server, but earlier versions of the Keycloak server might not work with later versions of the adapter.

Compatibility with older adapters

Newer versions of the Keycloak server potentially work with older versions of the adapters. However, some fixes of the Keycloak server may break compatibility with older versions of the adapters. For example, a new implementation of the OpenID Connect specification may not match older client adapter versions.

For this situation, you can use Compatibility modes. For OpenID Connect clients, the Admin Console includes OpenID Connect Compatibility Modes on the page with client details. With this option, you can disable some new aspects of the Keycloak server to preserve compatibility with older client adapters. For more details, see the tool tips of individual switches.

Upgrading the EAP adapter

To upgrade the WildFly adapter, complete the following steps:

Procedure
  1. Download the new adapter archive.

  2. Remove the previous adapter modules by deleting the WILDFLY_HOME/modules/system/add-ons/keycloak/ directory.

  3. Unzip the downloaded archive into WILDFLY_HOME.

Upgrading the JavaScript adapter

To upgrade a JavaScript adapter that has been copied to your web application, perform the following procedure.

Procedure
  1. Download the new adapter archive.

  2. Overwrite the keycloak.js file in your application with the keycloak.js file from the downloaded archive.

Upgrading the Node.js adapter

To upgrade a Node.js adapter that has been copied to your web application, perform the following procedure.

Procedure
  1. Download the new adapter archive.

  2. Remove the existing Node.js adapter directory

  3. Unzip the updated file into its place

  4. Change the dependency for keycloak-connect in the package.json of your application

Upgrading the Keycloak Admin Client

Be sure that you upgrade the Keycloak server before you upgrade the admin-client. Earlier versions of the admin-client might work with later versions of Keycloak server, but earlier versions of Keycloak server might not work with later versions of the admin-client. Therefore, use the admin-client version that matches the current Keycloak server version.