Migrate from Amazon Cognito to Keycloak

Moving a Cognito user pool to Keycloak is mostly a question of how you get users across without password hashes, and how you keep the sub claim your apps rely on. This page lays out what moves cleanly, the sequence, and what drives effort.

On this page

Migrate from Amazon Cognito to Keycloak: what it involves

The move is a realm build, a user migration and an app client cutover. You design a Keycloak realm to match the Cognito user pool's sign-in model, move identities into it, and then repoint each application's OIDC configuration from the pool's issuer to the realm. Teams usually reach this decision after a renewal or a MAU-based bill grows faster than expected, or when data residency or lock-in concerns make a regional pool hard to justify. Platform or security engineering normally owns the work, often with an implementation partner who handles the realm design, the migration scripts and the cutover runbook. Your internal team keeps ownership of the identity model and the application changes.

Effort and risk depend mostly on how many applications sit behind the pool, how many users have passwords, and how much logic lives in Lambda triggers. The main risk is the password hash. Cognito does not export password hashes, so you cannot copy existing credentials into Keycloak directly. You must choose between forcing a password reset for every user and running a sign-in-time migration, where Keycloak validates the password against Cognito on first login and then stores the user locally. Decide this early, because it shapes the user communication plan and the window during which both systems run. Confirm with AWS how long the pool stays available for sign-in-time checks in your account before you commit to a date.

Plan the cutover around the sub claim. Applications often store the Cognito sub as the user's primary key, so a new Keycloak user ID breaks their records unless you preserve the original value or keep a mapping table. Test this on a copy of the realm before any production change, and check each app client's redirect URIs, token lifetimes and scopes against the Keycloak client settings. Keycloak's server administration guide covers client and realm configuration. Ask your vendor or partner to document a rollback path for each application so that a failed cutover does not strand users between two identity systems.

Which Cognito capabilities map to Keycloak, and which need rework

This table maps each Cognito user pool capability to its Keycloak equivalent and marks it as clean, needs rework or gap. Read the status first, then the note, which flags what to confirm against the Keycloak version you deploy. The main takeaway is that protocol and federation features map well, while Lambda trigger logic and password hash continuity need deliberate design work.

Cognito capabilityKeycloak equivalentStatusNotes for the migration
User poolsRealms, one per tenant or environmentNeeds reworkRealms are separate security boundaries, so decide whether one pool becomes one realm. Export and import are per realm, and realm export is documented as limited for backup.
App clientsClients with redirect URIs and client secretsNeeds reworkRecreate each app client as a Keycloak client and confirm the allowed redirect URIs, token lifetimes and public or confidential settings for every application.
GroupsGroups and client rolesCleanMap Cognito groups to Keycloak groups and role mappings. Confirm how group claims appear in tokens for your applications before cutover.
Hosted UIKeycloak login pages with themesNeeds reworkKeycloak provides its own login pages that can be themed. Custom Cognito hosted UI styling and domain settings must be rebuilt, and your domain and certificate plan must be confirmed.
Federation with SAML and OIDC identity providersIdentity brokering with SAML and OIDC providersCleanKeycloak supports SAML 2.0 and OpenID Connect brokering. Confirm attribute mapping for each upstream provider and test first logins with real federated accounts.
MFAKeycloak authentication flows with OTP or WebAuthnNeeds reworkCognito MFA settings do not carry over. Rebuild required factors in authentication flows and confirm which second factors your Keycloak version supports and how enrollment is handled for existing users.
Custom attributesUser attributes and user profile configurationNeeds reworkDefine each custom attribute in the user profile before import. Confirm the attribute names and types so the sub claim and downstream claims stay stable.
Lambda triggersAuthenticators, event listeners and custom SPIsGapNo direct equivalent exists for Cognito triggers. Pre-authentication, post-confirmation and migration logic must be rewritten as Keycloak SPIs or flows, which requires development and testing.
Password hashesCredentials imported or verified at sign-inGapCognito does not export password hashes, so users must reset passwords or migrate at sign-in. Confirm your chosen method with Keycloak documentation and your security policy.

How to export Cognito profiles with ListUsers

The first thing to settle is what the export can and cannot carry. Profiles, attributes and account status come out of a Cognito user pool through the ListUsers API, and the export cannot include password hashes. That single limit decides the whole migration path, because Keycloak needs either a set of hashes to import with users' existing passwords or a way to verify passwords at sign-in. Cognito gives you neither in bulk. Run ListUsers against the pool with paging, and treat every returned record as a profile to move, not as a credential. Because ListUsers returns results in pages, your script must follow the pagination token until it is exhausted and must not assume it has the full population after one call. Confirm the current paging behavior and request parameters in the AWS Cognito API reference before you write the loop.

Keep a fixed set of fields for each user so the Keycloak import is predictable. The most important is the sub attribute, because applications store it as the stable user identifier and Keycloak must be configured to reproduce it, or every app will see new identities after cutover. Also keep username, the email and email_verified values, phone_number and phone_number_verified where used, cognito:user_status and whether the account is enabled, every custom attribute (names prefixed with custom:), and group memberships from AdminListGroupsForUser, which ListUsers does not return. Record MFA preference separately if your pool uses it. Store the output encrypted, in a restricted bucket or volume with access logging, delete it once the import is verified, and document the retention decision for your auditors.

Before you run the export in production, confirm three things with your own pool: the number of users and groups, which custom attributes contain personal data that your privacy notice covers, and whether any user status requires a reset before first sign-in. Ask your Keycloak operator to confirm how the realm will map sub and attribute names. Test the full export and import on a copy of the pool, and compare record counts and sample profiles between the two sides. The result of this step is the input for the choice between forced password resets and sign-in-time migration described in the next section.

What data moves and what integrations need rebuilding

Moving from Cognito to Keycloak splits into two kinds of work: data you can export and reload, and logic that lives in Cognito settings, app clients and Lambda triggers that you must rebuild in Keycloak. Each card below names the export path or rebuild task and what to confirm before cutover.

User profiles and attributes

Profile data such as username, email, phone number and custom attributes can be read through the Cognito ListUsers API, which pages results. Export it to a file you control, then map each standard and custom attribute to a Keycloak user attribute or profile field. Confirm which attributes are verified, which the user can edit, and whether any were fixed at pool creation, because those limits carry over to your mapping. Watch for the sub value: Cognito issues it per user, so decide whether Keycloak will keep the same identifier for downstream apps.

Password credentials (not exportable)

Cognito does not export password hashes, so passwords cannot be copied into Keycloak with the profile data. Your two options are a forced password reset for every user, or a sign-in-time migration where a custom authenticator checks the password against Cognito once and then stores the new credential in Keycloak. Confirm with your own Cognito configuration whether a sign-in-time check through the InitiateAuth API is acceptable for your security policy, and plan how users with MFA enrolled will re-register their factors.

Groups and roles

Cognito groups and their precedence values carry access decisions into your apps through token claims. In Keycloak, recreate them as groups or realm roles, then add client roles where an application needs scoped permissions. Map each Cognito group to a Keycloak group and confirm which claims your applications read, such as cognito:groups, and how they must appear in the new groups or roles claim. Test a user from each group end to end before cutover.

App clients and redirect URIs

Each Cognito app client has its own callback and sign-out URLs, allowed OAuth flows, scopes and token lifetimes. Recreate each one as a Keycloak OpenID Connect client in a realm, copying the exact redirect URIs, web origins and PKCE settings. Confirm the client secret handling for confidential clients, and confirm token lifetimes match what your applications expect. Mismatched redirect URIs are a common cause of failed sign-in after cutover.

Lambda triggers rebuilt as flows or SPIs

Cognito Lambda triggers such as pre sign-up, post confirmation, pre token generation and custom authentication run code at fixed points in the sign-in flow. In Keycloak, the equivalent logic goes into an authentication flow with custom authenticators, required actions, or event listeners written as Service Provider Interfaces. Inventory every trigger, document what each one reads and writes, and confirm which ones call external systems, since those calls must be reproduced and secured in the new platform.

Downstream API authorizers

APIs behind API Gateway or Lambda often validate Cognito-issued tokens with a JWT authorizer that points at the pool's issuer URL and expects specific audience and scope claims. Changing the issuer to a Keycloak realm URL breaks every validator until each one is updated, including its JWKS endpoint and expected claim names. List every API authorizer, record its issuer and audience settings, and test each one against a token from the new realm before you switch DNS or traffic.

Forced password resets or sign-in-time migration

In a forced reset, you import profiles into a Keycloak realm without passwords, then require every user to set a new password before they can sign in. The design is simple to explain and simple to test, because the realm is the only source of truth once the cutover date passes. The cost lands on users and on the help desk, since every account needs a reset email or an administrator action, and the reset flow must work for people who no longer control the address on file.

  • Predictable scope: every account is handled the same way, so the cutover checklist is short and easy to audit.
  • Support load: expect a spike of reset requests on cutover day, with some users unable to find the email.
  • Dormant users: accounts nobody uses still need a reset, so you must decide whether to import or retire them first.
  • MFA re-enrollment: users must usually register authenticators again, which often needs a separate verification step.
  • Single running period: Cognito can be switched off soon after the import, which limits how long two systems must be kept in sync.

Confirm with your application owners how reset emails are delivered, and whether your compliance evidence needs a record of each forced reset.

The migration sequence from inventory to decommission

This sequence moves Cognito users and app clients into Keycloak realms one application at a time, so each cutover is reversible and verified. Each step closes with a written output that the next step depends on. Cognito stays live until the team has confirmed the sub claim and login behavior for every application.

  1. Inventory pools, clients, triggers and dependent APIs

    Record every user pool, app client, custom attribute, group, resource server, domain and Lambda trigger (pre sign-up, post confirmation, pre token generation and similar). List every API, service and downstream system that reads the sub, cognito:groups or custom claims from tokens. Engineering owns the technical inventory and the application owners confirm their dependencies. The step is done when you hold a signed inventory that maps each app client to its consumers and each trigger to the business rule it enforces.

  2. Build a pilot realm with one non-critical app

    Create a Keycloak realm, configure the database and TLS in your own environment, and register one low-risk application as an OIDC client. Export a sample of users with ListUsers, which returns 60 users per request, and import them into the pilot realm for testing. Confirm that the Keycloak realm import produces the expected users, groups and roles. The step is done when the pilot app signs in through Keycloak with a test account and the team has a written list of gaps found during testing.

  3. Choose the password strategy and run both IdPs

    Decide between a forced password reset for all users and a sign-in-time migration, because Cognito does not export password hashes. Under sign-in-time migration, a custom user storage provider validates the password against Cognito on first login and stores the user in Keycloak. Keep Cognito live for the remaining applications while the pilot runs in parallel. The step is done when the security and compliance owners have approved the chosen strategy in writing and the parallel login path has been tested end to end.

  4. Cut over each app client and verify the sub claim

    Move one app client at a time from Cognito to a Keycloak client, rebuilding the Lambda trigger logic as Keycloak authentication flows, event listeners or SPI providers. Compare the sub value issued by Keycloak with the value stored in your application databases, and plan how existing records map to new identifiers before go-live. Keep the Cognito client available for rollback during the window you define. The step is done when each application's test suite passes and the sub mapping has been verified against real records, not only test accounts.

  5. Decommission Cognito after a retention period

    Once every app client is live on Keycloak, disable new sign-ups in Cognito and confirm no traffic still reaches the old pools through application logs or token metrics. Retain the Cognito export, configuration and the inventory under the retention rules your compliance team sets. Delete the user pools only after that period ends and the records are archived. The step is done when the decommission record shows no active clients, the retention schedule is documented and the Cognito pool deletion is confirmed by the owner of the AWS account.

Preserving the sub claim apps depend on

Applications rarely key their data on email addresses or usernames. They store the sub claim from the ID token, because it is meant to be a stable subject identifier, and every row that records an owner, a membership or an audit entry points at that value. When you move from Amazon Cognito to Keycloak, Keycloak issues its own subject identifiers for each user, and those values will not match the Cognito sub unless you deliberately carry them across. If nothing is done, existing references resolve to no one, and users may appear to have lost their data even though their profiles migrated correctly.

The practical fix is to keep the old Cognito sub as a stored value and expose it in tokens. Two common approaches are to import the Cognito sub as a custom user attribute during the profile export and to add a protocol mapper in the client scope that writes that attribute into a claim your applications read, such as a legacy_sub claim. Your application team then decides whether to map on the legacy value during a transition period or to rewrite stored references to the Keycloak identifier in a controlled backfill. The choice should be made per application and recorded before cutover, because it determines which claim your code reads after the switch. Confirm with your own identity team how Keycloak's sub is derived for each user, and whether your chosen approach changes it.

Test this in the pilot realm before any production cutover. Create a test user in Cognito with a known sub, migrate that user with the same method you plan to use in production, sign in to each application client, and confirm that the token's subject or legacy claim matches what the application has stored. Repeat the test for a user with stored records, a user in each group that drives authorization, and a user who signs in through a federated identity provider if you have one. Also check any Lambda trigger logic or downstream service that reads the sub directly. Treat a failed match as a blocking defect, because a broken subject link is hard to detect after users have started to sign in.

What drives migration cost and duration

This table lists the factors that change the effort of moving a Cognito user pool to Keycloak realms, with why each one moves cost and how to keep it under control. Read it before requesting a quote, since most drivers multiply across pools, clients and identity providers rather than adding up in a single line.

DriverWhy it moves costHow to keep it down
Number of user pools and app clientsEach pool maps to a realm or a set of realm configurations, and each app client needs its own redirect URIs, scopes, token settings and testing. Effort grows with every combination.Consolidate pools that share users and policies before migrating. Retire unused app clients first and confirm the inventory with your Cognito administrator.
Custom triggers (Lambda)Pre-authentication, post-confirmation, token generation and migration triggers hold business logic that must be rewritten as Keycloak authenticators, SPIs or event listeners, then tested.Inventory each trigger and remove logic that no longer applies. Confirm with the owning team which triggers are still required before scoping the rewrite.
Password strategyCognito exports no password hashes, so the choice between forced resets and sign-in-time migration changes support load, user communication and the code needed for the migration path.Decide the strategy early in writing. Estimate reset volume from recent sign-in activity, which you can pull from your own logs.
Number of federated identity providersEach SAML or OIDC identity provider connected to Cognito must be reconfigured as a Keycloak identity provider, with attribute mappings and certificate or metadata handling tested.List every federation and its attribute mappings. Ask whether any upstream partner must change its own configuration, since that work sits outside your control.
MFA re-enrollmentTOTP secrets and other second factors generally cannot be carried over in an export, so users may need to enroll again, which drives help desk volume and identity verification steps.Confirm which MFA methods are in use and whether your policy allows a verified re-enrollment flow. Plan the enrollment window with the service desk.
Hosting and high availability designKeycloak documents single-cluster, multi-cluster v2 and deprecated multi-cluster v1 designs, and each needs its own infrastructure, load balancing and failover testing.Match the design to the recovery requirement set by your organization. Ask the implementation partner to state which design is in scope in the written statement of work.
Database choiceKeycloak supports several production databases, and the synchronous replication that high availability requires adds licensing or managed service cost and operational work in some engines.Use a database your team already operates and backs up. Confirm the engine version against the supported list before selecting it.
Testing scopeEach app client, federated login, token lifetime, logout path and trigger replacement needs functional and security testing before cutover, and a parallel run may be needed.Define test cases per app client and per identity provider in the scope. Reuse one regression suite across environments to limit repeated work.

What usually goes wrong and how to prevent it

Most failed Cognito-to-Keycloak moves break at the edges: stored identifiers, sign-in continuity, and the operational habits around the export and upgrade tooling. The cards below cover the risks that tend to surface during cutover and the check to run before each one reaches users.

Sub claim changes break stored references

Applications often store the OIDC sub value as the foreign key for user rows, audit logs and entitlements. A Keycloak realm assigns its own user IDs, so a user who is imported without preserving the original identifier arrives with a different sub, and every stored reference points at nothing. Before cutover, decide whether the sub must be kept, confirm how your import path sets the user ID, and run a test where an existing account's stored records still resolve after sign-in.

Forced resets lock out inactive users

Because Cognito does not export password hashes, a forced reset means every user must set a new password before signing in. Users who no longer read the notification email, or who rarely sign in, become locked out at the moment they need access. Measure how many accounts have had no recent sign-in, decide whether a sign-in-time migration covers them, and test the reset email flow end to end with a non-production realm.

Realm export used as a backup

The kc.sh export command writes realm configuration to JSON, but Keycloak's own documentation warns that this is limited as a backup and restore mechanism. Teams that treat the export file as their recovery plan find that it does not capture everything needed to rebuild a live system. Keep a database-level backup as the recovery source, use the realm export for configuration review and version control, and rehearse a restore before go-live.

Stopping every node for export

The export process requires all Keycloak nodes to be stopped while it runs. In a clustered deployment, that means an outage window that someone must schedule, communicate and staff. Plan the export as a maintenance event with a confirmed window, a rollback path to the Cognito pool that remains active until sign-in is verified, and a named owner for the stop and restart sequence.

Schema upgrades on live data

Keycloak migrates its database schema automatically at startup by default. That behavior is convenient in development but risky when a new version starts against a production database holding migrated users and client configuration. For large deployments, the upgrading guide describes applying schema changes manually. Take a database snapshot, run the upgrade in a staging copy with the same data volume, and choose between automatic and manual migration before the production change window.

Token lifetime and redirect URI mismatches

App clients recreated in Keycloak often differ from their Cognito originals in redirect URIs, allowed origins, token lifetimes and refresh behavior. A single character mismatch in a callback URL stops sign-in for that application, and long or short token lifetimes change session behavior users notice. Compare every app client setting side by side, list each registered redirect URI against the application configuration, and test sign-out and token refresh in each application before switching DNS or traffic.

How the move differs by starting point

A single user pool with a handful of app clients is the simplest starting point. One realm can usually hold all the users, and the work concentrates on the clients and the sign-in path. The export is one pass of ListUsers paging, and the main decision is whether to force password resets or migrate users as they sign in, since Cognito does not export password hashes.

  • One realm, one set of clients: map each Cognito app client to a Keycloak client and keep the sub value stable for every user so existing applications still recognize accounts.
  • Small cutover window: with few users, a forced reset or a short freeze may be acceptable, but confirm the user count and support capacity before choosing.
  • Lambda triggers: list each trigger (pre sign-up, pre token generation and others) and decide which logic moves into Keycloak authenticators, mappers or custom SPIs.
  • Group and role mapping: translate Cognito groups into Keycloak groups or roles and check which token claims your applications read.
  • Parallel test realm: build the realm first, test sign-in with a copy of the clients, and only then repoint the production domains.

Before starting, confirm which applications read the sub claim, cognito:groups or other Cognito-specific claims, because those are the first things that break after a switch.",

Questions teams ask before moving from Cognito to Keycloak

What drives the cost of moving from Cognito to Keycloak?

The cost depends mostly on how many app clients, Lambda triggers, custom attributes and federated identity providers the user pool uses, and on how much of the login experience you want to rebuild. Keycloak itself is licensed under Apache 2.0, so the license line is zero, but you pay for the infrastructure that runs it, the production database, high availability, monitoring, backups and the people who operate and patch it. Migration work is a one-time cost, while hosting and operations recur. Ask any provider for a fixed-scope quote that lists each app client, trigger and attribute, and separates one-time migration work from recurring run costs.

How long does a Cognito to Keycloak migration take?

The timeline is set by the number of apps that must switch over, the trigger logic that must be rebuilt, and whether you use forced password resets or a sign-in-time migration. A pool with a few clients and simple profiles moves much faster than one with many federated sign-in paths and custom authentication flows. Sign-in-time migration keeps users signing in during a longer cutover window, while a bulk export with forced resets concentrates the user impact into a shorter period. Agree the cutover plan and the parallel-running period in writing before work starts, and confirm the schedule against your own change calendar.

What does the migration need from our own team?

You need owners who can decide on the business side and engineers who can change each application's OpenID Connect configuration. The business owners decide the password reset approach, the user communication and the cutover date. The platform team provides the infrastructure, database access, DNS, certificates and secrets handling. Application teams must update redirect URIs, token validation and any code that reads Cognito-specific claims. Security and compliance staff review the control evidence you will need for your assessment. Plan for named contacts in each group before the engagement starts.

Can our own engineers do the Cognito to Keycloak migration without a partner?

Yes, an experienced platform team can do it, provided they have operated a stateful service in production and can cover the cutover risk. The Cognito side is straightforward to export with ListUsers, which returns users in pages, but the export does not include password hashes, so you must choose a password strategy. On the Keycloak side, the team must configure realms, clients, group mappings and a supported production database, and plan high availability. Keycloak's own documentation warns that realm export and import are limited as a backup mechanism and that all nodes must be stopped during the process, so the team needs a tested runbook. A partner is useful when you need the work fixed in scope and delivered on a written schedule.

Can password hashes be recovered from Cognito for Keycloak?

In general, no. Cognito's ListUsers output gives you profiles, attributes and status, but not the stored password hashes, so the hashes cannot be copied into Keycloak through the standard export. That leaves two main options: force users to reset passwords after cutover, or migrate each user at sign-in by checking the password against Cognito once and then storing the result in Keycloak. Sign-in-time migration needs Cognito to remain reachable during the transition, and you must confirm with AWS how long your pool and its credentials will stay available. Confirm this behavior against the current Cognito documentation and your own pool before you choose.

How are Keycloak upgrades handled after the migration?

Keycloak publishes minor releases four times a year and major releases every two to three years, and since Keycloak 26.0 the project says breaking changes in a minor release are opt-in. This makes upgrades more predictable, but you still need a tested upgrade path for each release you adopt. Keycloak migrates its database schema automatically at startup by default, and large deployments can apply the SQL manually instead, as the upgrading guide suggests. The Keycloak Operator documentation strongly recommends manual approval mode for operator updates to avoid unintended upgrades. Ask any provider how they will test upgrades in a non-production realm before production, and who signs off on each change.

Does Keycloak keep the sub claim our applications depend on?

Keycloak issues OpenID Connect tokens with a sub claim, but its value is the Keycloak user identifier, which differs from the Cognito sub for the same person. Applications that store the Cognito sub as a foreign key will break unless you carry the old value across as an attribute or rewrite the stored references. Plan a mapping table from old subject to new subject, run it against every service that stores user identifiers, and test token validation in staging before cutover. Confirm the exact claim behavior in your Keycloak version and client configuration with your engineers before you commit to a date.

How DeployOpen scopes and runs the migration

DeployOpen plans, implements, customizes, integrates, hardens, backs up, upgrades, documents and supports self-hosted open-source platforms inside your own infrastructure. For a move from Amazon Cognito to Keycloak, that means agreeing the user export path, the password strategy, the app client mapping and the token contract in writing before any realm is built.

How we scope

  • Inventory every Cognito user pool, app client, identity provider and Lambda trigger in scope for the move.
  • Record which applications depend on the sub claim and define how it is preserved in the Keycloak realm.
  • Agree in writing whether users move by forced password reset or by sign-in-time migration, since Cognito does not export password hashes.

How we build

  • Build Keycloak realms, groups, roles and OIDC clients that mirror the agreed Cognito app client configuration.
  • Rebuild the logic from Lambda triggers as Keycloak authentication flows or extensions, tested against the agreed behavior.
  • Test sign-in, token claims, MFA enrollment and the password path against staging copies of each relying application.

How we hand over

  • Document the realm layout, client settings, export and import procedure, and the cutover runbook for your team.
  • Provide backup and restore notes, noting that realm export and import have limits as a backup mechanism and need all nodes stopped.
  • Walk your operations and security staff through the configuration so they can run and patch the platform after handover.

How we support

  • Support is available as a retainer for upgrades, Keycloak releases, patching and ongoing configuration changes after cutover.
  • Security testing of the migrated login flows and APIs can be scoped as a separate engagement with its own written terms.
  • Confirm with DeployOpen the retainer scope, response expectations and who owns each runbook before the project closes.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.