Another day, another… well, another few days spent trying to figure out why we couldn’t get some AWS Cognito functionality working. After much weeping and gnashing of teeth, we finally got it. And, because AWS’s docs are woefully lacking in this particular area, we wanted to blog it if only to help ourselves when we inevitably forget the solution and head to Google to figure it out in the future 🙂

The Goal: Using both migration and pre-signup triggers in the same User Pool

We’ve been working on a new admin for a while, and part of what we’re changing is how we’re handling authentication. Rather than building our own social sign-in and MFA handling, we decided to use Cognito to do the heavy lifting. In order to make this as seamless as possible for our users, we set out to use Cognito’s migration trigger, which works like this:

  1. User attempts to login.
  2. User doesn’t exist in Cognito’s user pool. Before erroring, Cognito triggers a migration Lambda.
  3. Our lambda checks against our own user database. If the password entered matches what we have on our end (or rather, the hash of what we have), the function returns the new user.
  4. Cognito creates the user and logs the user in.

That works fine by itself, but we also want to prevent new users from signing up to Cognito with an already-existing email address. So we have a pre-sign-up trigger. That looks like this:

  1. User attempts to sign up.
  2. Our custom lambda runs, and does a super quick check to see if their desired email already exists. If so, it returns an error and Cognito returns an error to the user.
  3. Else the user is created in Cognito.

The Problem: Pre-Signup triggers after Migration

Each of those triggers above works well by themselves. But when they’re both on the same user pool, here’s what happens:

  1. The migration flow (above) happens.
  2. The pre-signup flow (above) then happens.
  3. ERROR! The user’s email that we want to migrate exists already, so the pre-signup flow returns an error.

Even worse (and the reason we’re blogging this) is that, even though the migration flow looks like it works perfectly, the user isn’t actually created because the next step errors.

And compounding all this is the chained behaviour of the triggers isn’t documented anywhere we can find. The triggerSource in the event passed to the lambda is also unclear: PreSignUp_SignUp for “normal” signups, and PreSignUp_AdminCreateUser for when the signup trigger happens after a migration (UserMigration_Authentication).

So… ?

For now, we’re keying off the triggerSource values, but better documentation from AWS would be better.

The only other mention of this issue is from a comment in AWS’s forum 5 years ago. We’ve contacted AWS’s support, so hopefully they improve the documentation. In the meantime, if you’ve stumbled on this page trying to figure out why you’re getting migration errors, make sure you check out your pre-signup event 🙂