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 capability | Keycloak equivalent | Status | Notes for the migration |
|---|---|---|---|
| User pools | Realms, one per tenant or environment | Needs rework | Realms 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 clients | Clients with redirect URIs and client secrets | Needs rework | Recreate each app client as a Keycloak client and confirm the allowed redirect URIs, token lifetimes and public or confidential settings for every application. |
| Groups | Groups and client roles | Clean | Map Cognito groups to Keycloak groups and role mappings. Confirm how group claims appear in tokens for your applications before cutover. |
| Hosted UI | Keycloak login pages with themes | Needs rework | Keycloak 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 providers | Identity brokering with SAML and OIDC providers | Clean | Keycloak supports SAML 2.0 and OpenID Connect brokering. Confirm attribute mapping for each upstream provider and test first logins with real federated accounts. |
| MFA | Keycloak authentication flows with OTP or WebAuthn | Needs rework | Cognito 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 attributes | User attributes and user profile configuration | Needs rework | Define 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 triggers | Authenticators, event listeners and custom SPIs | Gap | No 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 hashes | Credentials imported or verified at sign-in | Gap | Cognito 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.
In a sign-in-time migration, Keycloak keeps a custom user storage provider or authenticator that checks the password against Cognito on the first login. When Cognito accepts the password, Keycloak stores the user locally with the new credential, and later logins never call Cognito. Users see little change, but the migration logic is code you must write, test, secure and eventually remove. Cognito also has to remain reachable and correctly configured for as long as unmigrated users may sign in.
- Gradual move: active users migrate on their own, so the support spike is smaller than with a forced reset.
- Dormant users: accounts that never sign in stay in Cognito, so you need a clear rule for when they are retired or reset.
- MFA handling: the authenticator can only verify the password, so you must decide whether MFA is re-enrolled at first sign-in.
- Dual running period: Cognito costs and access rules continue until the remaining user count is low enough to close out.
- Security review: the bridge holds credentials in transit and needs its own access controls, logging and threat model.
Confirm with your developers how the bridge is tested, and agree in writing when Cognito will be decommissioned.
Dormant accounts and MFA enrollment are where the two approaches differ most in practice. A forced reset treats every account the same and removes the question from the migration itself, but it asks inactive people to act. A sign-in-time migration leaves dormant accounts in Cognito, which means you keep paying for and securing a second system for them. Neither approach removes the need to decide what happens to accounts that never return.
- Inactive account policy: agree a cutoff for retiring, disabling or resetting accounts with no recent sign-in.
- Authenticator reuse: TOTP secrets and passkeys generally cannot be moved from Cognito, so plan for re-enrollment.
- Recovery paths: users without a working authenticator need a verified recovery route that does not weaken MFA.
- Privileged accounts: administrators should move first and under stricter checks, whichever approach you choose.
- Records: keep an auditable list of which accounts were retired, reset or migrated.
Confirm with your security team how MFA recovery is approved, and whether your audit scope covers the dormant account decision.
Both approaches require a period in which Cognito and Keycloak coexist, and that period is where operational risk accumulates. During it, you must keep application clients pointed at the correct identity provider, prevent conflicting profile changes, and watch sign-in failures from either side. The forced reset shortens this window because the cutover is a single event, while the sign-in-time bridge stretches it across the time it takes users to return.
- Routing: each application must know which provider handles a given login, and this must be tested before cutover.
- Profile changes: decide whether updates go to Cognito, Keycloak or both during the overlap.
- Monitoring: track sign-in success rates, bridge errors and remaining unmigrated users on a shared dashboard.
- Rollback: define the conditions under which you return to Cognito and how long that option stays open.
- Cost: Cognito charges continue while users remain there, so the overlap has a direct billing effect.
Confirm with your platform team who owns the cutover runbook, and what rollback looks like in your own environment.
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.
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.
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.
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.
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.
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.
| Driver | Why it moves cost | How to keep it down |
|---|---|---|
| Number of user pools and app clients | Each 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 strategy | Cognito 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 providers | Each 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-enrollment | TOTP 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 design | Keycloak 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 choice | Keycloak 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 scope | Each 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
subvalue 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.",
Organizations that run several user pools, often across AWS Regions or accounts, face a consolidation decision before the migration. A Cognito user pool is tied to one Region, so the estate may hold users in pools that were created for different products or markets. Keycloak uses realms within a server deployment, so you need to decide whether to merge pools into one realm, keep one realm per pool, or run separate Keycloak deployments.
- Realm layout first: decide between one realm per pool, one shared realm with groups, or separate deployments per Region, and record the reason for each choice.
- Duplicate email and username collisions: the same person may hold accounts in more than one pool, so define the matching rule before importing.
- High availability design: a multi-Region plan needs Keycloak's documented high availability architecture and a synchronously replicated database, which adds infrastructure and operating work.
- Per-Region export: run ListUsers against each pool separately and keep a checksum of each export to confirm counts after import.
- Clock and cutover order: move pools in a sequence that lets one realm go live and be monitored before the next.
Confirm with your platform team which Regions must keep serving users during the move, because that determines whether you can cut over one pool at a time.
When a pool federates with SAML identity providers, the users who arrive through federation are not stored with password hashes in Cognito, and their identity depends on the external provider. Keycloak supports SAML 2.0 and OpenID Connect and can act as a broker to upstream identity providers, so the federation links can often be rebuilt rather than the users copied. The key question is which accounts should be recreated locally and which should keep signing in through their upstream provider.
- Federated versus native users: separate the two groups in the export, since federated users usually do not need a password reset.
- Identity provider rebuild: configure each SAML identity provider in Keycloak with the same entity ID, signing certificate and attribute mapping that the Cognito configuration used.
- Attribute mapping: check that the SAML assertion attributes map to the same Keycloak user attributes that your applications read.
- Metadata and certificate rotation: ask each upstream provider's administrator to add the Keycloak endpoints before cutover, and confirm the signing certificate lifetime.
- Sign-in path testing: test each federated provider with a real test account from that provider.
Confirm with each federation partner whether they must approve a change to the relying party settings, since that approval can set the schedule more than the technical work does.
A pool that must run on-premises, in a customer datacenter or an air-gapped network, starts with a different assumption: there is no managed AWS service to lean on. Keycloak runs on infrastructure you control, so the migration plan has to include the database, the TLS and certificate chain, backups, patching and the operating team before the first user is imported. The export from Cognito still happens in AWS, so the data path needs a secure transfer and a plan for where the export files are stored.
- Hosting and database: choose a supported production database such as PostgreSQL and size the environment for your user count and availability target.
- Export handling: move the exported profile data through an approved path, encrypt it at rest and delete staging copies after import.
- Operator and upgrades: if you run Kubernetes, the Keycloak Operator is an option, and its documentation recommends manual approval mode for operator updates.
- Backups and restore: the realm export and import commands have documented limits as a backup method and require all nodes to be stopped, so plan database-level backups instead.
- Air-gapped updates: plan how security patches and new Keycloak releases reach an isolated network.
Confirm your hosting, backup and patching obligations with the team that owns the environment before choosing a date.
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.

