マルチステップサインイン
ユーザーがサインアップを完了した後、サインインに進むことができます。Amplify Auth のサインインフローはマルチステップのプロセスになる場合があります。必要なステップは、MFA 設定の管理ページで説明されているように認証リソースを定義する際に提供した設定によって決まります。
設定によっては、ユーザーのサインインを完了するためにさまざまな API を呼び出す必要がある場合があります。サインインフローの次のステップを特定するには、サインイン結果の nextStep パラメータを確認してください。
成功した場合、サインイン API は AuthSignInResult を返します。結果の nextStep プロパティを確認して、追加のサインインステップが必要かどうかを確認してください。
func signIn(username: String, password: String) async { do { let signInResult = try await Amplify.Auth.signIn(username: username, password: password) switch signInResult.nextStep { case .confirmSignInWithSMSMFACode(let deliveryDetails, let info): print("SMS code sent to \(deliveryDetails.destination)") print("Additional info \(String(describing: info))")
// Prompt the user to enter the SMSMFA code they received // Then invoke `confirmSignIn` api with the code
case .confirmSignInWithTOTPCode: print("Received next step as confirm sign in with TOTP code")
// Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code
case .confirmSignInWithOTP(let deliveryDetails): print("Email code sent to \(deliveryDetails.destination)")
// Prompt the user to enter the Email MFA code they received // Then invoke `confirmSignIn` api with the code
case .continueSignInWithFirstFactorSelection(let allowedFactors): print("Received next step as continue sign in by selecting first factor") print("Allowed factors \(allowedFactors)")
// Prompt the user to select the first factor they want to use // Then invoke `confirmSignIn` api with the factor
case .confirmSignInWithPassword: print("Received next step as confirm sign in with password")
// Prompt the user to enter the password // Then invoke `confirmSignIn` api with the password case .continueSignInWithTOTPSetup(let setUpDetails): print("Received next step as continue sign in by setting up TOTP") print("Shared secret that will be used to set up TOTP in the authenticator app \(setUpDetails.sharedSecret)") // Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code
case .continueSignInWithEmailMFASetup: print("Received next step as continue sign in by setting up email MFA") // Prompt the user to enter the email address they wish to use for MFA // Then invoke `confirmSignIn` api with the email address
case .continueSignInWithMFASetupSelection(let allowedMFATypes): print("Received next step as continue sign in by selecting MFA type to setup") print("Allowed MFA types \(allowedMFATypes)")
// Prompt the user to select the MFA type they want to setup // Then invoke `confirmSignIn` api with the MFA type
case .continueSignInWithMFASelection(let allowedMFATypes): print("Received next step as continue sign in by selecting MFA type") print("Allowed MFA types \(allowedMFATypes)") // Prompt the user to select the MFA type they want to use // Then invoke `confirmSignIn` api with the MFA type case .confirmSignInWithCustomChallenge(let info): print("Custom challenge, additional info \(String(describing: info))") // Prompt the user to enter custom challenge answer // Then invoke `confirmSignIn` api with the answer case .confirmSignInWithNewPassword(let info): print("New password additional info \(String(describing: info))") // Prompt the user to enter a new password // Then invoke `confirmSignIn` api with new password case .resetPassword(let info): print("Reset password additional info \(String(describing: info))") // User needs to reset their password. // Invoke `resetPassword` api to start the reset password // flow, and once reset password flow completes, invoke // `signIn` api to trigger signin flow again. case .confirmSignUp(let info): print("Confirm signup additional info \(String(describing: info))") // User was not confirmed during the signup process. // Invoke `confirmSignUp` api to confirm the user if // they have the confirmation code. If they do not have the // confirmation code, invoke `resendSignUpCode` to send the // code again. // After the user is confirmed, invoke the `signIn` api again. case .done: // Use has successfully signed in to the app print("Signin complete") } } catch let error as AuthError{ print ("Sign in failed \(error)") } catch { print("Unexpected error: \(error)") }}nextStep プロパティは AuthSignInStep という enum 型です。その値に応じて、コードは以下のいずれかのアクションを実行する必要があります:
SMS MFA でサインインを確認する
次のステップが confirmSignInWithSMSMFACode の場合、Amplify Auth はユーザーに SMS でランダムなコードを送信し、ユーザーがそれを正常に受け取ったかどうかを確認するのを待っています。このステップを処理するには、アプリの UI でユーザーにコードの入力を促す必要があります。ユーザーがコードを入力したら、実装は Amplify Auth の confirmSignIn API にその値を渡す必要があります。
注記:サインイン結果には AuthCodeDeliveryDetails メンバーも含まれます。SMS 受信者の部分的な電話番号など、コードの配信に関する追加情報が含まれています。
func confirmSignIn(confirmationCodeFromUser: String) async { do { let signInResult = try await Amplify.Auth.confirmSignIn(challengeResponse: confirmationCodeFromUser) if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } } catch let error as AuthError { print("Confirm sign in failed \(error)") } catch { print("Unexpected error: \(error)") }}func confirmSignIn(confirmationCodeFromUser: String) -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.confirmSignIn(challengeResponse: confirmationCodeFromUser) }.sink { if case let .failure(authError) = $0 { print("Confirm sign in failed \(authError)") } } receiveValue: { signInResult in if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } }}TOTP MFA でサインインを確認する
次のステップが confirmSignInWithTOTPCode の場合、セットアップ時に関連付けられた認証アプリから TOTP コードを入力するようユーザーに促してください。コードは 30 秒ごとに変わる 6 桁の数字です。ユーザーは 30 秒のウィンドウが切れる前にコードを入力する必要があります。
ユーザーがコードを入力したら、実装は Amplify Auth の confirmSignIn API にその値を渡す必要があります。
func confirmSignIn(totpCode: String) async { do { let signInResult = try await Amplify.Auth.confirmSignIn(challengeResponse: totpCode) if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } } catch { print("Confirm sign in failed \(error)") }}func confirmSignIn(totpCode: String) -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.confirmSignIn(challengeResponse: totpCode) }.sink { if case let .failure(authError) = $0 { print("Confirm sign in failed \(authError)") } } receiveValue: { signInResult in if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } }}メール MFA でサインインを確認する
次のステップが confirmSignInWithOTP の場合、Amplify Auth はユーザーのメールアドレスにランダムなコードを送信し、ユーザーがそれを正常に受け取ったかどうかを確認するのを待っています。このステップを処理するには、アプリの UI でユーザーにコードの入力を促す必要があります。ユーザーがコードを入力したら、実装は Amplify Auth の confirmSignIn API にその値を渡す必要があります。
func confirmSignIn(confirmationCodeFromUser: String) async { do { let signInResult = try await Amplify.Auth.confirmSignIn(challengeResponse: confirmationCodeFromUser) if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } } catch let error as AuthError { print("Confirm sign in failed \(error)") } catch { print("Unexpected error: \(error)") }}func confirmSignIn(confirmationCodeFromUser: String) -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.confirmSignIn(challengeResponse: confirmationCodeFromUser) }.sink { if case let .failure(authError) = $0 { print("Confirm sign in failed \(authError)") } } receiveValue: { signInResult in if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } }}MFA の選択でサインインを続行する
次のステップが continueSignInWithMFASelection の場合、ユーザーは使用する MFA メソッドを選択する必要があります。Amplify Auth は現在、SMS、TOTP、メールを MFA メソッドとしてサポートしています。ユーザーが MFA メソッドを選択したら、実装は confirmSignIn API を使用して選択した MFA メソッドを Amplify Auth に渡す必要があります。
func confirmSignInWithTOTPAsMFASelection() async { do { let signInResult = try await Amplify.Auth.confirmSignIn( challengeResponse: MFAType.totp.challengeResponse)
if case .confirmSignInWithTOTPCode = signInResult.nextStep { print("Received next step as confirm sign in with TOTP") }
} catch { print("Confirm sign in failed \(error)") }}func confirmSignInWithTOTPAsMFASelection() -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.confirmSignIn( challengeResponse: MFAType.totp.challengeResponse) }.sink { if case let .failure(authError) = $0 { print("Confirm sign in failed \(authError)") } } receiveValue: { signInResult in if case .confirmSignInWithTOTPCode = signInResult.nextStep { print("Received next step as confirm sign in with TOTP") } }}メールセットアップでサインインを続行する
次のステップが continueSignInWithEmailMFASetup の場合、ユーザーはサインインプロセスを完了するためにメールアドレスを提供する必要があります。この値をユーザーから収集したら、confirmSignIn API を呼び出して続行してください。
// Confirm sign in with Email Setupcase .continueSignInWithEmailMFASetup: print("Received next step as continue sign in by setting up email MFA") // Prompt the user to enter the email address they wish to use for MFA // Then invoke `confirmSignIn` api with the email addressTOTP セットアップでサインインを続行する
次のステップが continueSignInWithTOTPSetup の場合、ユーザーはサインインプロセスを完了するために TOTP コードを提供する必要があります。このステップは TOTPSetupDetails 型の関連値を返し、TOTP の生成に使用されます。TOTPSetupDetails は getSetupURI というヘルパーメソッドを提供しており、ネイティブパスワードマネージャーによる TOTP 関連付けに使用できる URI を生成できます。例えば、Apple プラットフォームで URI を使用すると、プラットフォームのネイティブパスワードマネージャーがアカウントと TOTP を関連付けるよう促します。より高度なユースケースでは、TOTPSetupDetails に含まれる sharedSecret を使って QR コードを生成したり、認証アプリに手動で入力したりすることもできます。
認証アプリがセットアップされると、ユーザーは TOTP コードを生成してライブラリに提供し、サインインプロセスを完了できます。
// Confirm sign in with TOTP setupcase .continueSignInWithTOTPSetup(let setUpDetails): /// appName parameter will help distinguish the account in the Authenticator app let setupURI = try setUpDetails.getSetupUri(appName: "<Your_App_Name>>") print("TOTP Setup URI: \(setupURI)")func confirmSignInWithTOTPSetup(totpCodeFromAuthenticatorApp: String) async { do { let signInResult = try await Amplify.Auth.confirmSignIn( challengeResponse: totpCodeFromAuthenticatorApp)
if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } } catch { print("Confirm sign in failed \(error)") }}func confirmSignInWithTOTPSetup(totpCodeFromAuthenticatorApp: String) -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.confirmSignIn( challengeResponse: totpCodeFromAuthenticatorApp) }.sink { if case let .failure(authError) = $0 { print("Confirm sign in failed \(authError)") } } receiveValue: { signInResult in if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } }}MFA セットアップ選択でサインインを続行する
次のステップが continueSignInWithMFASetupSelection の場合、ユーザーはセットアップしたい利用可能な MFA メソッドを選択する必要があります。ユーザーがセットアップする MFA メソッドを選択したら、実装は confirmSignIn API に選択した MFA メソッドを渡す必要があります。
func continueSignInWithEmailMFASetupSelection() async { do { let signInResult = try await Amplify.Auth.confirmSignIn( challengeResponse: MFAType.email.challengeResponse)
if case .confirmSignInWithTOTPCode = signInResult.nextStep { print("Received next step as confirm sign in with TOTP") }
} catch { print("Confirm sign in failed \(error)") }}func continueSignInWithEmailMFASetupSelection() -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.confirmSignIn( challengeResponse: MFAType.email.challengeResponse) }.sink { if case let .failure(authError) = $0 { print("Confirm sign in failed \(authError)") } } receiveValue: { signInResult in if case .confirmSignInWithTOTPCode = signInResult.nextStep { print("Received next step as confirm sign in with TOTP") } }}カスタムチャレンジでサインインを確認する
次のステップが confirmSignInWithCustomChallenge の場合、Amplify Auth はカスタム認証チャレンジの完了を待っています。チャレンジは、カスタムサインインフローのセットアップ時に設定した Lambda トリガーに基づいています。このステップを完了するには、ユーザーにカスタムチャレンジの答えを入力するよう促し、その答えを confirmSignIn API に渡す必要があります。
func confirmSignIn(challengeAnswerFromUser: String) async { do { let signInResult = try await Amplify.Auth.confirmSignIn(challengeResponse: challengeAnswerFromUser) if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } } catch let error as AuthError { print("Confirm sign in failed \(error)") } catch { print("Unexpected error: \(error)") }}func confirmSignIn(challengeAnswerFromUser: String) -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.confirmSignIn(challengeResponse: challengeAnswerFromUser) }.sink { if case let .failure(authError) = $0 { print("Confirm sign in failed \(authError)") } } receiveValue: { signInResult in if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } }}新しいパスワードでサインインを確認する
次のステップが confirmSignInWithNewPassword の場合、Amplify Auth は続行前にユーザーが新しいパスワードを入力する必要があります。ユーザーに新しいパスワードを求め、confirmSignIn API に渡してください。
func confirmSignIn(newPasswordFromUser: String) async { do { let signInResult = try await Amplify.Auth.confirmSignIn(challengeResponse: newPasswordFromUser) if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } } catch let error as AuthError { print("Confirm sign in failed \(error)") } catch { print("Unexpected error: \(error)") }}func confirmSignIn(newPasswordFromUser: String) -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.confirmSignIn(challengeResponse: newPasswordFromUser) }.sink { if case let .failure(authError) = $0 { print("Confirm sign in failed \(authError)") } } receiveValue: { signInResult in if signInResult.isSignedIn { print("Confirm sign in succeeded. The user is signed in.") } else { print("Confirm sign in succeeded.") print("Next step: \(signInResult.nextStep)") // Switch on the next step to take appropriate actions. // If `signInResult.isSignedIn` is true, the next step // is 'done', and the user is now signed in. } }}パスワードのリセット
resetPassword を受け取った場合、パスワードをリセットしないと認証フローを続行できません。次のステップは resetPassword API を呼び出してパスワードリセットフローを開始することです。完了したら signIn を呼び出してサインインフローを再開してください。
func resetPassword(username: String) async { do { let resetPasswordResult = try await Amplify.Auth.resetPassword(for: username) print("Reset password succeeded.") print("Next step: \(resetPasswordResult.nextStep)") } catch let error as AuthError { print("Reset password failed \(error)") } catch { print("Unexpected error: \(error)") }}func resetPassword(username: String) -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.resetPassword(for: username) }.sink { if case let .failure(authError) = $0 { print("Reset password failed \(authError)") } } receiveValue: { resetPasswordResult in print("Reset password succeeded.") print("Next step: \(resetPasswordResult.nextStep)") }}サインアップの確認
次のステップとして confirmSignUp を受け取った場合、メールや電話番号などのユーザー情報を確認しないとサインアップを続行できません。次のステップは confirmSignUp API を呼び出してサインアップ確認フローを進めることです。
func confirmSignUp(for username: String, with confirmationCode: String) async { do { let confirmSignUpResult = try await Amplify.Auth.confirmSignUp( for: username, confirmationCode: confirmationCode ) print("Confirm sign up result completed: \(confirmSignUpResult.isSignUpComplete)") } catch let error as AuthError { print("An error occurred while confirming sign up \(error)") } catch { print("Unexpected error: \(error)") }}func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCancellable { Amplify.Publisher.create { try await Amplify.Auth.confirmSignUp(for: username, confirmationCode: confirmationCode) }.sink { if case let .failure(authError) = $0 { print("An error occurred while confirming sign up \(authError)") } } receiveValue: { _ in print("Confirm signUp succeeded") }}完了
done が返された場合、サインインフローは完了し、ユーザーは正常に認証されています。便宜上、SignInResult には isSignedIn プロパティも提供されており、次のステップが done の場合は true になります。