amazon-cognito-identity-js setupMFA problems

I am attempting to setup MFA for users after they reset their passcode. The code runs smoothly until I hit mfaSetup, specifically the line user.associateSoftwareToken(). When I pass in ‘this’ instead of user, I get the following error:

Uncaught (in promise) TypeError: callback is undefined

When I pass in user I get Uncaught (in promise) TypeError: callback.onFailure is not a function

I am truly at a loss of what to do and would appreciate any help.

Code below:


  const onSubmit = (event) => {
    event.preventDefault();

    const authDetails = new AuthenticationDetails({
      Username: email,
      Password: password
    });

    const user = new CognitoUser({
      Username: email,
      Pool: UserPool
    });

    user.authenticateUser(authDetails, {
      onSuccess: (data) => {
        console.log('onSuccess:', data);
        if (location.pathname === '/') {
          // navigate('dashboard');
        }
      },
      onFailure: (err) => {
        console.error('onFailure:', err);
      },
      newPasswordRequired: (data) => {
        console.log(data);
        setNewPasscodeRequired(true);
      },
      mfaRequired: (data) => {
        console.log('mfa required');
      },
      mfaSetup: (challengeName, challengeParameters) => {
        console.log('in mfa setup');
        console.log(user.Session);
        user.associateSoftwareToken(user, {
          onFailure: (err) => {
            console.error('onFailure', err);
          },
          onSuccess: (result) => {
            console.log(result);
          }
        });
      },
      selectMFAType: (challengeName, challengeParameters) => {
        console.log(challengeName, challengeParameters);
        user.sendMFASelectionAnswer('SOFTWARE_TOKEN_MFA', this);
      },
      totpRequired: (secretCode) => {
        console.log(secretCode);
        const challengeAnswer = prompt('Please input the TOTP code.', '');
        user.sendMFACode(challengeAnswer, this, 'SOFTWARE_TOKEN_MFA');
      },
      associateSecretCode: (secretCode) => {
        const challengeAnswer = prompt('Please input the TOTP code.', '');
        user.verifySoftwareToken(challengeAnswer, 'My TOTP device', this);
      }
    });
  };

  const onSubmitPasscode = (event) => {
    event.preventDefault();

    if (passwordFirst !== passwordSecond) {
      alert('the two inputs provided are not the same');
    } else {
      const user = new CognitoUser({
        Username: email,
        Pool: UserPool
      });

      const authDetails = new AuthenticationDetails({
        Username: email,
        Password: password
      });

      user.authenticateUser(authDetails, {
        onFailure: (err) => {
          console.error('onFailure:', err);
        },
        onSuccess: (result) => {
          console.log(result);
        },
        newPasswordRequired: (userAttributes, requiredAttributes) => {
          console.log(userAttributes);
          console.log(requiredAttributes);
          delete userAttributes.email_verified;
          delete userAttributes.phone_number_verified;
          delete userAttributes.phone_number;
          console.log(userAttributes);
          user.completeNewPasswordChallenge(passwordFirst, userAttributes, {
            onFailure: (err) => {
              console.error('onFailure:', err);
            },
            onSuccess: (result) => {
              console.log('call result: ', result);
            },
            mfaSetup: (challengeName, challengeParameters) => {
              console.log('in mfa setup');
              console.log(user.Session);
              user.associateSoftwareToken(this, {
                onFailure: (err) => {
                  console.error('onFailure', err);
                },
                onSuccess: (result) => {
                  console.log(result);
                }
              });
            },
            selectMFAType: (challengeName, challengeParameters) => {
              console.log(challengeName, challengeParameters);
              user.sendMFASelectionAnswer('SOFTWARE_TOKEN_MFA', this);
            },
            totpRequired: (secretCode) => {
              console.log(secretCode);
              const challengeAnswer = prompt('Please input the TOTP code.', '');
              user.sendMFACode(challengeAnswer, this, 'SOFTWARE_TOKEN_MFA');
            },
            associateSecretCode: (secretCode) => {
              const challengeAnswer = prompt('Please input the TOTP code.', '');
              user.verifySoftwareToken(challengeAnswer, 'My TOTP device', this);
            }
          });
        }
      });
    }
  };

  const onMFASetup = () => {
    const user = new CognitoUser({
      Username: email,
      Pool: UserPool
    });

    const authDetails = new AuthenticationDetails({
      Username: email,
      Password: passwordFirst
    });

    console.log(email);
    console.log(passwordFirst);

    user.authenticateUser(authDetails, {
      onFailure: (err) => {
        console.error('onFailure:', err);
      },
      onSuccess: (result) => {
        console.log(result);
      },
      mfaSetup: (challengeName, challengeParameters) => {
        user.associateSoftwareToken(this);
      },
      selectMFAType: (challengeName, challengeParameters) => {
        user.sendMFASelectionAnswer('SOFTWARE_TOKEN_MFA', this);
      },
      totpRequired: (secretCode) => {
        const challengeAnswer = prompt('Please input the TOTP code.', '');
        user.sendMFACode(challengeAnswer, this, 'SOFTWARE_TOKEN_MFA');
      },
      mfaRequired: (codeDeliveryDetails) => {
        const verificationCode = prompt('Please input verification code', '');
        user.sendMFACode(verificationCode, this);
      }
    });
  };

  const sendVerificationPin = (event) => {
    event.preventDefault();
    const user = new CognitoUser({
      Username: email,
      Pool: UserPool
    });

    user.forgotPassword({
      onSuccess: (result) => {
        console.log('call result: ', result);
      },
      onFailure: (err) => {
        alert(err);
      }
    });
  };

  const onResetPassword = (event) => {
    event.preventDefault();

    console.log('in reset');

    const user = new CognitoUser({
      Username: email,
      Pool: UserPool
    });

    console.log('user made');

    if (passwordFirst !== passwordSecond) {
      alert('the two inputs provided are not the same');
    } else {
      console.log('inputs are the same');
      user.confirmPassword(pin, passwordSecond, {
        onSuccess() {
          console.log('Password confirmed!');
          window.location.reload(true);
        },
        onFailure(err) {
          console.log('Password not confirmed!');
          console.log(err);
        }
      });
    }
  };

  return (
    <div>
      {!newPasscodeRequired && !forgotPassword && !setupMFA && (
        <div>
          <form onSubmit={onSubmit}>
            <input type="text" required value={email} onChange={(e) => setEmail(e.target.value)} />
            <input
              type="text"
              required
              value={password}
              onChange={(e) => setPassword(e.target.value)}
            />
            <button type="submit">Login</button>
          </form>
          <button onClick={(e) => setForgotPassword(true)}>
            <Typography sx={{ paddingX: 5 }}>Forgot password?</Typography>
          </button>
        </div>
      )}
      {newPasscodeRequired && (
        <div>
          <form onSubmit={onSubmitPasscode}>
            <Typography>New Password</Typography>
            <input type="text" required onChange={(e) => setPasswordFirst(e.target.value)} />
            <Typography>New Password Again</Typography>
            <input type="text" required onChange={(e) => setPasswordSecond(e.target.value)} />
            <Typography>New Password Requirements</Typography>
            <Typography>
              At least 8 characters long, requiring upper and lower case letters, numbers, and
              special characters
            </Typography>
            <button type="submit">Submit new passcode</button>
          </form>
        </div>
      )}
      {forgotPassword && !newPasscodeRequired && (
        <div>
          <form onSubmit={sendVerificationPin}>
            <Typography>Please input the email for the account</Typography>
            <input type="text" required onChange={(e) => setEmail(e.target.value)} />
            <button type="submit">Send verification pin</button>
          </form>
          <form onSubmit={onResetPassword}>
            <Typography>Input the verification pin sent to your email below</Typography>
            <input type="text" required onChange={(e) => setPin(e.target.value)} />
            <Typography>New Password</Typography>
            <input type="text" required onChange={(e) => setPasswordFirst(e.target.value)} />
            <Typography>New Password Again</Typography>
            <input type="text" required onChange={(e) => setPasswordSecond(e.target.value)} />
            <Typography>New Password Requirements</Typography>
            <Typography>
              At least 8 characters long, requiring upper and lower case letters, numbers, and
              special characters
            </Typography>
            <button type="submit">Reset Password</button>
          </form>
        </div>
      )}
      {setupMFA && (
        <div>
          <div>SetupMFA</div>
          <button onClick={(e) => onMFASetup()}>Generate QR Code</button>
        </div>
      )}
    </div>
  );
};