Skip to content

Commit 58eb248

Browse files
authored
feat(passwordless): Fix issue of not being able to change auth factor selection (#285)
1 parent 43a3625 commit 58eb248

File tree

4 files changed

+52
-13
lines changed

4 files changed

+52
-13
lines changed

authenticator/src/main/java/com/amplifyframework/ui/authenticator/AuthenticatorViewModel.kt

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

authenticator/src/main/java/com/amplifyframework/ui/authenticator/data/UserInfo.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,15 @@ package com.amplifyframework.ui.authenticator.data
22

33
import com.amplifyframework.ui.authenticator.enums.SignInSource
44

5-
internal data class UserInfo(val username: String, val password: String?, val signInSource: SignInSource)
5+
internal data class UserInfo(
6+
val username: String,
7+
val password: String?,
8+
val signInSource: SignInSource,
9+
val selectedAuthFactor: AuthFactor? = null
10+
) {
11+
override fun toString() = "UserInfo(" +
12+
"username=$username, " +
13+
"password=***, " +
14+
"signInSource=$signInSource, " +
15+
"selectedAuthFactor=$selectedAuthFactor)"
16+
}

authenticator/src/main/java/com/amplifyframework/ui/authenticator/ui/PasskeyCreated.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,5 @@ fun PasskeyCreated(
8181

8282
@Composable
8383
private fun Passkey(credential: AuthWebAuthnCredential) {
84-
Text(credential.friendlyName ?: "Unknown Passkey") // todo String resource
84+
Text(credential.friendlyName ?: stringResource(R.string.amplify_ui_authenticator_unknown_passkey))
8585
}

authenticator/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
<!-- Passkey Created Screen -->
4444
<string name="amplify_ui_authenticator_existing_passkeys">Existing Passkeys</string>
45+
<string name="amplify_ui_authenticator_unknown_passkey">Unknown Provider</string>
4546

4647
<!-- Select Auth Factor Screen -->
4748
<string name="amplify_ui_authenticator_or">or</string>

0 commit comments

Comments
 (0)