Sometimes we run into questions that seem simple, but that have a very complex answer. In this blog post we will explain why “Can I migrate between two Amazon Cognito User Pools” is one of those question, and why it usually leads to a new set of questions, like:
- Where do your users exist (do they federate from a different Identity Provider (IdP), or are they in the User Pool?)
- Are you using MFA in Cognito
- Which configuration settings can you change?
- Are you okay with a migration process in the application?
- Will all users sign in during a certain timeframe?
- Do you want to keep your endpoints and identifiers, or are new endpoints okay?
Lets look at why we are asking those questions, and which Cognito components are tricky to deal with.
The configuration of a User Pool can be described by the API, or managed in an Infrastructure as Code tool. This makes it easy to recreate with the same settings. However, besides the new endpoints and ids (see below), you will have to update the federation settings (of you are using sign in through a third party).
Eg. If you are federating users from Active Directory (AD) using SAML, you will have to set up a new integration on the AD side as well, so that user can sign in via AD/SAML. This is the same process as setting up this IdP for the first time.
Endpoints and Ids
If you create a new user pool, it will get a new id. This means that the following things will change. Usually this is not a problem, as these are expected changes (if you migrate to a different product, similar things will change).
- The User Pool Id
- The App Client Ids and Secrets (you also create new App Clients)
- The domain used for the hosted UI. Technically you can move it, but this will include downtime. Using a new domain will always be easier (and give you more control about step-by-step updates and rollbacks)
- The User Pool Id and App Client Id are also part of the Tokens that Cognito returns. If you’re verifying them in your application (which you should), or are using a managed integration between an AWS service and Cognito (eg. Api Gateway), you will have to update these too.
Users and Groups
This is the difficult part: while there are APIs to list/describe users and groups, there is no way to export the password (hash) or the MFA (seed) of a user. This means that in the worst case scenario you have to disable MFA and all users will have to reset their password before they can log in again. There are a few solutions, but none of them are ideal.
Problem: You are using MFA in Cognito
This is the worst case scenario for a migration. There is no way to export or set MFA seeds in Cognito, and usually disabling MFA for everyone is not going to be an option
Problem: You are using the sub attribute in your application
The sub attribute is an unique identifier for every user, and migrating users will create a new identifier. To work around this, you could use a different (custom) attribute to safe an identifier in, and update your application to use that. Filling that attribute comes with its own complexities, though.
Option 1: You are using federation / sign in through a third party
You’re in luck! Since the user and their password exist in the other system, you can setup a new federation and users will still be able to sign in (but make sure you’ve read the “Configuration” section above).
If you want to go this route to make migration (and failover) easier, there are third party IdPs that you can use via SAML/OIDC. Although in some cases it might make more sense to integrate directly with them (either in Cognito Identity Pools or in the application) instead of putting User Pools in between. One reason to keep Cognito, is that you can create multiple App Clients (and thus applications) on one pool (and this can be done with the IaC tool you are already using). Whereas if you integrate directly, you have to configure everything in the external service (and depending on the protocol you are using, this can be hard to debug)
Option 2: You don’t mind resetting all passwords.
This is also doable, you can export all users, import them in the new pool and make them set a new password to sign in (if this is a limited set of internal users, you could also set a password for them, but you’d want them to pick their own either way)
There is even an AWS solution (read: Open Source software that you have to manage yourself) that can be used to do the export once or on a schedule (eg. to create backups). Make sure to also check the limitations.
Option 3: Migrating on first sign-in
You can add a Lambda Function to the new User Pool (there is example code, but you’d have to manage this yourself). This function will get the username and password, and can check the original pool and write the existing password to the new pool if the password is correct. Docs:
This has some downsides:
- The old User Pool needs to stay around until the migration is complete (you pay for active users, so this does not have to be a cost problem)
- This can take a long time, and potential never finish (if you have users that don’t sign in regularly)
There is a lot of complexity to deal with, so the short answer to our original question is “it depends”.
If you have a workload where this question is relevant, you probably also want to give feedback to AWS (eg. via your Account Manager). If the service would provide a way to export and import Users and Groups, this would be a lot easier. Not being able to export password-hashes and MFA-seeds (even in a way that only Cognito can read them), is currently limiting multiple solutions.