Migrating from Keycloak

Migrating from Keycloak

On this page

Keycloak is a popular Identity and Access Management (IAM) system, for use in cloud native environments. A software company might choose this option when beginning its OAuth and OpenID Connect journey, and integrating security into web, mobile and API components.

At a later time, the company may decide that the Curity Identity Server, which is also cloud native, and has a free community edition, is a better fit for their requirements. OAuth and OpenID Connect are portable standards, so the migration can be managed in an organized and efficient manner, to export and import various types of data. The main steps are summarized later in this article.

Curity provides recommendations on how best to apply the OAuth framework to your applications. Firstly, a strong security profile is recommended. Secondly, key behaviors can be extended, to enable companies to implement their use cases. Some Curity concepts may be new to Keycloak users, so they are described first.

Data Protection Concepts

The Implementing Zero Trust APIs article summarizes the architecture Curity recommends when protecting data in APIs, which can be implemented without much code, or any adverse impact on API development:

  • Each API verifies a JWT access tokens on every request, in a zero trust manner
  • Opaque tokens are returned to internet clients, as a privacy best practice
  • An API gateway introspects opaque access tokens, then forwards JWTs to APIs
  • Each API uses claims from the JWT to implement its business authorization

With Keycloak, it is common to start managing authorization by configuring roles against users, then delivering JWTs to internet clients. It is still possible to do this, if you want to maintain existing security behavior.. When migrating to the Curity Identity Server though, you may also want to compare your existing API security design to Curity's recommendations.

Authentication Concepts

OpenID Connect provides a powerful authentication model for your web and mobile apps. Your Identity and Access Management (IAM) system implements the authorization server role from RFC6749. The app simply implements a code flow, after which authentication can work in many ways. Although the application code is simple, meeting some requirements will require a high level of extensibility within the IAM system.

It is common to provide a default username and password login method, to ensure that no users are blocked from signing in, though you will usually need to go beyond that. An example is the trend to support passwordless logins, where some users provide their identity using solutions built on WebAuthn, passkeys or digital wallets.

If you sketch out your desired logic for authentication, it will typically look like a flow chart. Curity provides two main mechanisms for implementing the logic, via Authenticators and Authentication Actions. It is usually critical to ensure a single user account, regardless of the authentication methods used, and actions enable this. See the Account Linking article for some examples.

Migrate Configuration

In Keycloak, a real-world installation will typically use a database such as PostgreSQL, to store all identity data. In the Curity Identity Server, user accounts and token related data are stored in a database, but security configuration settings are instead backed up to XML.

Import Configuration

In a simple setup you can manually add the configuration via the Admin UI of the Curity Identity Server. In more complex setups you may use scripts to read the configuration from the source system and send it to the Curity Identity Server either via the RESTCONF API or by using the CLI. Full details about the configuration schema are available in the configuration reference.

Most commonly you will use PATCH operations to merge data into the existing configuration:

curl -k -s \
-X PATCH "$RESTCONF_BASE_URL" \
-u "$ADMIN_USER:$ADMIN_PASSWORD" \
-H 'Content-Type: application/yang-data+xml' \
-d @./config.xml

A configuration with a single OAuth client is shown below. Once the technique is understood, it can be used to manage many different resources:

<data xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
  <profiles xmlns="https://curity.se/ns/conf/base">
    <profile>
      <id>token-service</id>
      <type xmlns:as="https://curity.se/ns/conf/profile/oauth">as:oauth-service</type>
      <settings>
        <authorization-server xmlns="https://curity.se/ns/conf/profile/oauth">
          <client-store>
            <config-backed>
              <client>
                <id>spa-client</id>
                <client-name>spa-client</client-name>
                <description>Demo Single Page Application</description>
                <secret>secret2</secret>
                <redirect-uris>https://www.example.com</redirect-uris>
                <scope>openid</scope>
                <scope>profile</scope>
                <capabilities>
                  <code/>
                </capabilities>
              </client>
            </config-backed>
          </client-store>
        </authorization-server>
      </settings>
    </profile>
  </profiles>
</data>

You can use the CLI to set values or even merge data into the existing configuration:

idsh
configure
load merge ./config.xml
commit
exit
exit

A configuration with a single OAuth client is shown below. Once the technique is understood, it can be used to manage many different identity resources:

<config xmlns="http://tail-f.com/ns/config/1.0">
  <profiles xmlns="https://curity.se/ns/conf/base">
    <profile>
      <id>token-service</id>
      <type xmlns:as="https://curity.se/ns/conf/profile/oauth">as:oauth-service</type>
      <settings>
        <authorization-server xmlns="https://curity.se/ns/conf/profile/oauth">
          <client-store>
            <config-backed>
              <client>
                <id>spa-client</id>
                <client-name>spa-client</client-name>
                <description>Demo Single Page Application</description>
                <secret>secret2</secret>
                <redirect-uris>https://www.example.com</redirect-uris>
                <scope>openid</scope>
                <scope>profile</scope>
                <capabilities>
                  <code/>
                </capabilities>
              </client>
            </config-backed>
          </client-store>
        </authorization-server>
      </settings>
    </profile>
  </profiles>
</config>

Parameterize Configuration

The Curity Identity Server allows you to export the configuration as a whole or in parts into an XML file. Sensitive values are encrypted and, if defined, placeholders for parameters can be filled in during deployment. As a result, you can put the configuration file under version control and use it in your deployment pipelines.

You should only need to do the import work once, in an early stage of your deployment pipeline, typically a development environment. You can then use the same parameterized configuration in all environments. This avoids data duplication and de-risks your production rollout. See the IAM Configuration Best Practices article for further details on managing configuration in the Curity Identity Server.

Design Deployment

If possible, aim to deploy the Curity Identity Server as a replacement for Keycloak, and use the same external URLs. Aim for minimal code or configuration changes in your APIs or user facing applications.

Deployment Resources

Both Keycloak and the Curity Identity Server are most commonly deployed as Docker containers. The deployment of a standalone instance is shown below, and includes a backed up configuration. In a real-world deployment, you will create a custom Docker image that includes other resources, such as customizations to the look and feel, or plugins that extend security behavior:

docker run -it -p 6749:6749 -p 8443:8443 \
-e CONFIG_ENCRYPTION_KEY="$KEY" \
-e ADMIN='true' \
-v "$(pwd)/config-backup.xml":/opt/idsvr/etc/init/config.xml \
curity.azurecr.io/curity/idsvr:latest

Migrate Endpoints

In Keycloak, you would define a realm, perhaps with a name such as default. Applications typically then download a list of endpoints from the OpenID Connect metadata endpoint, at a location like this:

https://login.example.com/realms/default/.well-known/openid-configuration

In the Curity Identity Server, the path for each endpoint can be configured separately, so you can maintain existing URLs if required. You can also create copies of endpoints for special use cases, such as providing a second token endpoint that requires Mutual TLS. Any edits are immediately available in OpenID Connect metadata.

edit endpoints

Multi-tenancy

Most commonly a single Keycloak realm is used, representing the authorization server, which is the central source of trust for your applications. In more specialized setups, you might want to migrate multiple realms, so that you have more than one authorization server, and data isolation between them.

You can manage this by creating a Curity Identity Server profile for each Keycloak realm. If required, you can also assign server roles to control which instances map to which profiles. For further details on advanced deployments, see the Multi-tenancy and Deployment Concepts articles.

Implement your Look and Feel

Once deployment is on track, it is common to focus early on login screens, to ensure that they are visually aligned with applications. Keycloak enables you to provide custom themes using HTML templates, CSS and message files, then assign each theme to one or more applications.

The Curity Identity Server provides a default modern look and feel for all user facing screens. To quickly update it for your company's brand, use the look and feel section of the Admin UI, which saves customizations to the configuration.

The Curity Identity Server also supports a custom look and feel per client. More detailed customizations can be made using the UI Builder, which enables you to edit HTML assets and receive fast feedback. The template system enables customization without duplication, and edited resources are usually then deployed to a custom docker image.

Migrate API Permissions

In Keycloak it is common to use role based security and to migrate roles you need to import them as custom claims. An end-to-end use of roles is explained in the implementing role based security tutorial. In a simple setup this means you would provide values such as these, either by entering them in the Admin UI, or by calling the RESTCONF API:

<scopes>
  <scope>
    <id>openid</id>
    <description>Standard OpenID Connect scope</description>
    <claims>role</claims>
  </scope>
</scopes>
<claims>
  <claim>
    <name>roles</name>
    <description>User Roles</description>
    <value-provided-by>account-manager-claims-provider</value-provided-by>
  </claim>
</claims>

Scopes and Claims

Roles only enable partial authorization. A more complete solution should use scopes for high level checks, and claims for the detailed business authorization. Keycloak scopes are defined in its Admin UI, and custom claims can be provided via protocol mappers.

In the Curity Identity Server, scopes are composed of claims, and scopes are also configured against clients. The token designer provides complete control over which claims are included in which tokens, or from the User Info endpoint.

Extensible Claims

Use of claims is a high value area when protecting your data, and in many cases you will need to include claims from your business data, or APIs, at the time of token issuance. If you have implemented custom protocol mappers in Keycloak, migrate to claims value providers in the Curity Identity Server.

Migrate Clients

When migrating clients, the Curity Identity Server enables you to maintain existing values for Client IDs and Client Secrets, to prevent you from needing to reconfigure your applications. The details can be typed into the Admin UI, or saved via the RESTCONF API or CLI, as described in the earlier section on migrating configuration.

Migrate Crypto Assets

Cryptographic material, including PKCS#12 files used for token signing, certificates and keys used for TLS or mutual TLS, or trust stores, can be imported into the Curity Identity Server's configuration. The easiest option when first getting set up, is to do so via the facilities menu in the Admin UI. Crypto resources can then be referenced by any other resources that use them, such as advanced clients, or token issuers.

Secrets used by the Curity Identity Server are always imported into configuration in a protected manner, and are also exported in this form. The GitOps Configuration Management tutorial shows how to provide secrets using a config encryption key, while also using parameterized configuration.

Migrate Users

The Curity Identity Server uses Account Manager and Credential Manager abstractions for reading user accounts and for interacting with password hashes. This means you have choices for how you migrate users. It is possible for the Curity Identity Server to connect directly to the Keycloak database, though this requires you to implement Java or Kotlin plugins.

It is often simpler to migrate users to Curity's database schema, and this will need to be done separately per environment. An ETL script can use either SCIM or GraphQL to save users. The schema of the Curity Identity Server includes an attributes field, which is usually stored as JSON. This is used to store any custom identity data against users, and can include Keycloak roles.

Credentials in standard formats can usually be imported without changing them, as long as the same algorithm details are used for password transformation. This can ensure no impact on end users who provide usernames and passwords, who will continue to login with their existing credentials.

User data can also include child lists, such as linked accounts and registered WebAuthn devices. If required, this can also be populated via APIs. It is not usually essential to migrate this data, and you may prefer to instead re-link accounts or devices on demand, the next time an end-user uses that authentication flow.

Migrate Authentication Workflows

Keycloak supports multiple authentication methods, in the Identity Providers area of its Admin UI, which is equivalent to authenticators in the Curity Identity Server. Connections can be configured for OIDC and SAML 2.0 compliant IDPs, as well as for social logins. These settings are migrated by entering equivalent values in the Admin UI of the Curity Identity Server, for a development environment, after which they can then be included in the parameterized configuration.

Keycloak also enables you to add Flows under the Authentication section of its Admin UI, and assign Steps to each flow. Any logic here can be migrated to actions in the Curity Identity Server. An Actions Toolbox is provided, to enable you to compose behavior in a drag and drop manner, or write simple scripts that operate on attributes. It is also possible to add new bespoke actions via plugins, then configure them from the Admin UI.

Deploy and Operate

Once integrated, your teams will continue to use the Curity Identity Server for many future security use cases. Tutorials and code examples from guides will be used by engineering teams. Developers can also develop plugins to integrate custom behavior when required. Meanhile DevOps teams will use monitoring features to ensure that the system is running reliably.

Conclusion

The Curity Identity Server is designed to support migrations from other systems. Therefore, migrating from Keycloak can be planned and managed efficiently, as a deployment job. If your existing OAuth and OpenID Connect applications are coded in a portable way, changes to your applications will be minimal.