Action Triggered MFA Using enrollWith and challengeWith

Problem statement

How to use enrollWith and challengeWith via the Action to force users to enroll into a new factor if they already enrolled in one other?

Solution

If the user is already enrolled into one factor, let’s say phone, the enrollWith command will fail as the user must verify the existing factor before enrolling an additional factor. Here is a sample Action script that shows the correct sequence:

exports.onExecutePostLogin = async (event, api) => {
  console.log(`Action started`);
  const alreadyEnrolled = event.user.enrolledFactors;
  console.log(`Check if the user already has any MFA enrollments`);
  if (alreadyEnrolled.length > 0) {
    console.log(`The user already enrolled in some MFAs. Needs to pass a challenge.`);
    api.authentication.challengeWithAny([
      { type: 'phone' }, { type: 'push-notification' }, { type: 'email' }, { type: 'otp' }
    ]); // here we ask the user to verify the existing MFA
    const enrolledInOTP = (event.user.enrolledFactors || []).filter(f => f.type === 'otp').map(f => ({ type: f.type }));
    if (enrolledInOTP.length === 0) { // here we check if the user is enrolled into OTP 
      console.log(`The user is not enrolled in OTP`);
      api.authentication.enrollWith(
        { type: 'otp' }
      ) // here we invite the user to enrol into OTP
    }
  } else {
    console.log(`The user doesn't have any MFAs`);
    api.authentication.enrollWithAny([
      { type: 'phone' }, { type: 'push-notification' }, { type: 'email' }, { type: 'otp' }
    ]) // here we allow the user to enrol into one of the factors listed above
  }
};

Please also review this article for more information Customize MFA Enrollments in New Universal Login.