@@ -316,8 +316,8 @@ internal class AuthenticatorViewModel(
316316 startSignIn(info)
317317 }
318318
319- private suspend fun startSignIn (info : UserInfo ) = startSignInJob {
320- val options = getSignInOptions()
319+ private suspend fun startSignIn (info : UserInfo , preferredFirstFactorOverride : AuthFactor ? = null ) = startSignInJob {
320+ val options = getSignInOptions(preferredFirstFactorOverride = preferredFirstFactorOverride )
321321 when (val result = authProvider.signIn(info.username, info.password, options)) {
322322 is AmplifyResult .Error -> handleSignInFailure(info, result.error)
323323 is AmplifyResult .Success -> handleSignInSuccess(info, result.data)
@@ -402,33 +402,56 @@ internal class AuthenticatorViewModel(
402402
403403 private suspend fun handleFactorSelectionRequired (info : UserInfo , availableFactors : Set <AuthFactor >? ) {
404404 if (availableFactors == null ) {
405- val exception = AuthException (" Missing available AuthFactorTypes" , " Please open a bug with Amplify" )
405+ val exception =
406+ AuthException (" Missing available AuthFactorTypes" , AmplifyException .REPORT_BUG_TO_AWS_SUGGESTION )
406407 handleGeneralFailure(exception)
407408 return
408409 }
409410
410411 // Auto-select a single auth factor
411412 if (availableFactors.size == 1 ) {
412- confirmSignIn(info, availableFactors.first().challengeResponse)
413+ val newInfo = info.copy(selectedAuthFactor = availableFactors.first())
414+ confirmSignIn(newInfo, availableFactors.first().challengeResponse)
413415 return
414416 }
415417
418+ // User has not selected an auth factor yet.
419+ // We need to keep track of a mutating selection here as `onSelect` may be called multiple times as user
420+ // retries after encountering an error (e.g. incorrect password, passkey error, etc).
421+ var currentUserInfo = info.copy(selectedAuthFactor = null )
422+
416423 val newState = stateFactory.newSignInSelectFactorState(
417424 username = info.username,
418425 availableFactors = availableFactors,
419426 onSelect = { authFactor ->
420- val passwordField = (currentState as ? BaseStateImpl )?.form?.fields?.get(Password )
421- val password = passwordField?.state?.content
422- val newInfo = info.copy(password = password)
423- confirmSignIn(newInfo, authFactor.challengeResponse)
427+ val password = if (authFactor is AuthFactor .Password ) {
428+ val passwordField = (currentState as ? BaseStateImpl )?.form?.fields?.get(Password )
429+ passwordField?.state?.content
430+ } else {
431+ null
432+ }
433+
434+ // If a user has already previously selected an auth factor then we need to restart the sign in
435+ // flow in order to select a factor again.
436+ val flowRestartRequired = currentUserInfo.selectedAuthFactor != null
437+
438+ currentUserInfo = currentUserInfo.copy(password = password, selectedAuthFactor = authFactor)
439+
440+ if (flowRestartRequired) {
441+ // Call signIn to restart the flow but select the same factor
442+ startSignIn(currentUserInfo, preferredFirstFactorOverride = authFactor)
443+ } else {
444+ // Use confirmSignIn to select an auth factor for the first time
445+ confirmSignIn(currentUserInfo, authFactor.challengeResponse)
446+ }
424447 }
425448 )
426449 moveTo(newState)
427450 }
428451
429452 private fun handleTotpSetupRequired (info : UserInfo , totpSetupDetails : TOTPSetupDetails ? ) {
430453 if (totpSetupDetails == null ) {
431- val exception = AuthException (" Missing TOTPSetupDetails" , " Please open a bug with Amplify " )
454+ val exception = AuthException (" Missing TOTPSetupDetails" , AmplifyException . REPORT_BUG_TO_AWS_SUGGESTION )
432455 handleGeneralFailure(exception)
433456 return
434457 }
@@ -445,7 +468,9 @@ internal class AuthenticatorViewModel(
445468
446469 private suspend fun handleMfaSetupSelectionRequired (info : UserInfo , allowedMfaTypes : Set <MFAType >? ) {
447470 if (allowedMfaTypes.isNullOrEmpty()) {
448- handleGeneralFailure(AuthException (" Missing allowedMfaTypes" , " Please open a bug with Amplify" ))
471+ handleGeneralFailure(
472+ AuthException (" Missing allowedMfaTypes" , AmplifyException .REPORT_BUG_TO_AWS_SUGGESTION )
473+ )
449474 return
450475 }
451476
@@ -467,7 +492,9 @@ internal class AuthenticatorViewModel(
467492
468493 private suspend fun handleMfaSelectionRequired (info : UserInfo , allowedMfaTypes : Set <MFAType >? ) {
469494 if (allowedMfaTypes.isNullOrEmpty()) {
470- handleGeneralFailure(AuthException (" Missing allowedMfaTypes" , " Please open a bug with Amplify" ))
495+ handleGeneralFailure(
496+ AuthException (" Missing allowedMfaTypes" , AmplifyException .REPORT_BUG_TO_AWS_SUGGESTION )
497+ )
471498 return
472499 }
473500
0 commit comments