@@ -330,8 +330,56 @@ final class SignInStateMachine
330
330
createEmailMfaRequest (event),
331
331
ChallengeNameType .selectMfaType when hasUserResponse =>
332
332
createSelectMfaRequest (event),
333
- ChallengeNameType .mfaSetup when hasUserResponse =>
334
- createMfaSetupRequest (event),
333
+ ChallengeNameType .mfaSetup =>
334
+ (() async {
335
+ final allowedMfaTypes = _allowedMfaTypes;
336
+ if (allowedMfaTypes == null || allowedMfaTypes.isEmpty) {
337
+ throw const InvalidUserPoolConfigurationException (
338
+ 'No MFA types are allowed for setup.' ,
339
+ recoverySuggestion: 'Check your user pool MFA configuration.' ,
340
+ );
341
+ }
342
+ // Exclude MfaType.sms from consideration
343
+ final mfaTypesForSetup = allowedMfaTypes.difference ({MfaType .sms});
344
+ if (mfaTypesForSetup.isEmpty) {
345
+ throw const InvalidUserPoolConfigurationException (
346
+ 'No eligible MFA types are available for setup.' ,
347
+ recoverySuggestion: 'Check your user pool MFA configuration.' ,
348
+ );
349
+ }
350
+ if (mfaTypesForSetup.length == 1 ) {
351
+ final mfaType = mfaTypesForSetup.first;
352
+ if (mfaType == MfaType .totp) {
353
+ _enableMfaType = MfaType .totp;
354
+ _totpSetupResult ?? = await associateSoftwareToken ();
355
+ if (hasUserResponse) {
356
+ return createMfaSetupRequest (event);
357
+ } else {
358
+ // Need to prompt user for the TOTP code
359
+ return null ;
360
+ }
361
+ } else if (mfaType == MfaType .email) {
362
+ _enableMfaType = MfaType .email;
363
+ if (hasUserResponse) {
364
+ return createEmailMfaSetupRequest (event);
365
+ } else {
366
+ // Need to prompt user for the email verification code
367
+ return null ;
368
+ }
369
+ } else {
370
+ throw InvalidUserPoolConfigurationException (
371
+ 'Unsupported MFA type: ${mfaType .name }' ,
372
+ recoverySuggestion: 'Check your user pool MFA configuration.' ,
373
+ );
374
+ }
375
+ } else if (hasUserResponse) {
376
+ // Handle user's selection
377
+ return createMfaSetupRequest (event);
378
+ } else {
379
+ // Need to prompt user to select an MFA type
380
+ return null ;
381
+ }
382
+ })(),
335
383
ChallengeNameType .newPasswordRequired when hasUserResponse =>
336
384
createNewPasswordRequest (event),
337
385
_ => null ,
@@ -674,6 +722,24 @@ final class SignInStateMachine
674
722
});
675
723
}
676
724
725
+ /// Compeletes set up of an email MFA.
726
+ @protected
727
+ Future <RespondToAuthChallengeRequest > createEmailMfaSetupRequest (
728
+ SignInRespondToChallenge event,
729
+ ) async {
730
+ _enableMfaType = MfaType .email;
731
+ return RespondToAuthChallengeRequest .build ((b) {
732
+ b
733
+ ..challengeName = ChallengeNameType .emailOtp
734
+ ..challengeResponses.addAll ({
735
+ CognitoConstants .challengeParamUsername: cognitoUsername,
736
+ CognitoConstants .challengeParamEmailMfaCode: event.answer,
737
+ })
738
+ ..clientId = _authOutputs.userPoolClientId
739
+ ..clientMetadata.addAll (event.clientMetadata);
740
+ });
741
+ }
742
+
677
743
/// Selects an MFA type to use for sign-in.
678
744
@protected
679
745
Future <RespondToAuthChallengeRequest > createSelectMfaRequest (
0 commit comments