From e834de28a1cb1c158eef9dae027145d3e9d9a4e2 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Mon, 25 Nov 2024 11:49:51 -0800 Subject: [PATCH 01/19] Add initial android sign in doc updates --- .../connect-your-frontend/sign-in/index.mdx | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index 78ffb2ea697..a6cc6c2f125 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -1114,6 +1114,227 @@ func socialSignInWithWebUI() -> AnyCancellable { Your application's users can also sign in using passwordless methods. To learn more, visit the [concepts page for passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/) + + +### New auth flow type + +In order to facilitate the new passwordless sign in options, Cognito is introducing a new auth flow type known as `USER_AUTH`. This flow is designed to be flexible and supports both password and passwordless sign in factors. + + + + +```java +// The callingActivity parameter should always be set if your app is +// expecting to use WebAuthn as not setting this option will lead to +// a sub-optimal user experience when authenticating via WebAuthn +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build(); +Amplify.Auth.signIn( + "username", + null, + options, + result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()), + error -> Log.e("AuthQuickstart", error.toString()) +); +``` + + + + +```kotlin +// The callingActivity parameter should always be set if your app is +// expecting to use WebAuthn as not setting this option will lead to +// a sub-optimal user experience when authenticating via WebAuthn +val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build() +Amplify.Auth.signIn( + "username", + null, + options, + { result -> + Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") + }, + { error -> + Log.e("AuthQuickstart", "Failed to sign in", error) + } +) +``` + + + + +```kotlin +try { + // The callingActivity parameter should always be set if your app is + // expecting to use WebAuthn as not setting this option will lead to + // a sub-optimal user experience when authenticating via WebAuthn + val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = null, + options = options + ) + Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} +``` + + + + +```java +// The callingActivity parameter should always be set if your app is +// expecting to use WebAuthn as not setting this option will lead to +// a sub-optimal user experience when authenticating via WebAuthn +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build(); +RxAmplify.Auth.signIn("username", null, options) + .subscribe( + result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()), + error -> Log.e("AuthQuickstart", error.toString()) + ); +``` + + + + + +### Sign In with a Preferred Challenge for First Factor + +The USER_AUTH sign in flow will support the following methods of first factor authentication: `AuthFactorType.WEB_AUTHN`, `AuthFactorType.EMAIL_OTP`, `AuthFactorType.SMS_OTP`, `AuthFactorType.PASSWORD`, and `AuthFactorType.PASSWORD_SRP`. + +If the desired first factor is known before the sign in flow is initiated it can be passed to the initial sign in call: + + + + +```java +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.EMAIL_OTP) + .callingActivity(callingActivity) + .build(); +``` + + + + +```kotlin +val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.EMAIL_OTP) + .callingActivity(callingActivity) + .build() +``` + + + + + +```kotlin +// PASSWORD_SRP / PASSWORD +// sign in with preferred challenge as password +// note password must be provided in same step +const { nextStep } = await signIn({ + username: state.username, + password: state.password, + options: { + authFlowType: "USER_AUTH", + preferredChallenge: "PASSWORD_SRP" // or "PASSWORD" + }, +}); + +// nextStep.signInStep === 'DONE' +handleNextSignInStep(nextStep); + +// WEB_AUTHN +// sign in with preferred challenge as web authn +// no user input required at this step +const { nextStep } = await signIn({ + username: state.username, + options: { + authFlowType: "USER_AUTH", + preferredChallenge: "WEB_AUTHN" + }, +}); + +// nextStep.signInStep === 'DONE' +handleNextSignInStep(nextStep); + +// EMAIL_OTP +// sign in with preferred challenge as email otp +// no user input required at this step +const { nextStep } = await signIn({ + username: state.username, + options: { + authFlowType: "USER_AUTH", + preferredChallenge: "EMAIL_OTP" + }, +}); + +// nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE' +handleNextSignInStep(nextStep); + +// SMS_OTP +// sign in with preferred challenge as sms otp +// no user input required at this step +const { nextStep } = await signIn({ + username: state.username, + options: { + authFlowType: "USER_AUTH", + preferredChallenge: "SMS_OTP" + }, +}); + +// nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_SMS_CODE' +handleNextSignInStep(nextStep); +``` + +Note that if the preferred auth factor is not available, the preference will be ignored and the flow will continue to first factor discovery. + +### Passwordless Sign In with First Factor Discovery + +When multiple first factor options are available and none are set as preferred in InitiateAuth API call (or preferred challenge is not available), Amplify JS continues to a new sign in step `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`: + +```ts +interface ContinueSignInWithFirstFactorSelection { + signInStep: 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION'; + availableChallenges?: ChallengeName[]; +} +``` + +```ts +const { nextStep } = await signIn({ + username: state.username, + options: { + authFlowType: "USER_AUTH", + } +}); + +// nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION' +handleNextSignInStep(nextStep); +``` + +To initiate an available first factor, the desired first factor type is passed to confirm sign in as the challenge response. The next sections will that step for each `AuthFactorType`. + + + ### SMS OTP {/* blurb with supplemental information about handling sign-in, events, etc. */} From 31d17fdf33251a67f9d953d880e4c7a7c31c2456 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Tue, 26 Nov 2024 11:36:18 -0800 Subject: [PATCH 02/19] Add sign in with preferred challenge --- .../connect-your-frontend/sign-in/index.mdx | 350 +++++++++++++++--- 1 file changed, 307 insertions(+), 43 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index a6cc6c2f125..70440034755 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -280,10 +280,12 @@ The `signIn` API response will include a `nextStep` property, which can be used | `CONFIRM_SIGN_IN_WITH_TOTP_CODE` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | | `CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | | `CONFIRM_SIGN_IN_WITH_OTP` | The sign-in must be confirmed with a code from the user (sent via SMS or Email). Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_PASSWORD` | The sign-in must be confirmed with the password from the user. Complete the process with `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION` | The user must select their mode of MFA verification to setup. Complete the process by passing either `MFAType.EMAIL.challengeResponse` or `MFAType.TOTP.challengeResponse` to `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` | The user must select their mode of first factor authentication. Complete the process by passing the desired mode to the `challengeResponse` field of `confirmSignIn`. | | `RESET_PASSWORD` | The user must reset their password via `resetPassword`. | | `CONFIRM_SIGN_UP` | The user hasn't completed the sign-up flow fully and must be confirmed via `confirmSignUp`. | | `DONE` | The sign in process has been completed. | @@ -608,6 +610,8 @@ Following sign in, you will receive a `nextStep` in the sign-in result of one of | `CONFIRM_SIGN_IN_WITH_TOTP_CODE` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | | `CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | | `CONFIRM_SIGN_IN_WITH_OTP` | The sign-in must be confirmed with a code from the user (sent via SMS or Email). Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_PASSWORD` | The sign-in must be confirmed with the password from the user. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` | The user must select their mode of first factor authentication. Complete the process by passing the desired mode to the `challengeResponse` field of `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION` | The user must select their mode of MFA verification to setup. Complete the process by passing either `MFAType.EMAIL.challengeResponse` or `MFAType.TOTP.challengeResponse` to `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | @@ -1223,6 +1227,51 @@ If the desired first factor is known before the sign in flow is initiated it can ```java +// PASSWORD_SRP / PASSWORD +// sign in with preferred challenge as password +// note password must be provided in same step +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or AuthFactorType.PASSWORD + .callingActivity(callingActivity) + .build(); +Amplify.Auth.signIn( + "username", + "password", + options, + result -> { + // result.getNextStep() === 'DONE' + handleNextSignInStep(result); + }, + error -> Log.e("AuthQuickstart", "Failed to sign in", error) +); + +// WEB_AUTHN +// sign in with preferred challenge as web authn +// no user input required at this step +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) + .callingActivity(callingActivity) + .build(); +Amplify.Auth.signIn( + "username", + null, + options, + result -> { + // result.getNextStep() === 'DONE' + handleNextSignInStep(result); + }, + error -> Log.e("AuthQuickstart", "Failed to sign in", error) +); + +// EMAIL_OTP +// sign in with preferred challenge as email otp +// no user input required at this step AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions .builder() @@ -1230,82 +1279,297 @@ AWSCognitoAuthSignInOptions options = .preferredFirstFactor(AuthFactorType.EMAIL_OTP) .callingActivity(callingActivity) .build(); +Amplify.Auth.signIn( + "username", + null, + options, + result -> { + // result.getNextStep() === 'CONFIRM_SIGN_IN_WITH_OTP' + handleNextSignInStep(result); + }, + error -> Log.e("AuthQuickstart", "Failed to sign in", error) +); + +// SMS_OTP +// sign in with preferred challenge as sms otp +// no user input required at this step +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.SMS_OTP) + .callingActivity(callingActivity) + .build(); +Amplify.Auth.signIn( + "username", + null, + options, + result -> { + // result.getNextStep() === 'CONFIRM_SIGN_IN_WITH_OTP' + handleNextSignInStep(result); + }, + error -> Log.e("AuthQuickstart", "Failed to sign in", error) +); ``` - + ```kotlin +// PASSWORD_SRP / PASSWORD +// sign in with preferred challenge as password +// note password must be provided in same step +val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or AuthFactorType.PASSWORD + .callingActivity(callingActivity) + .build() +Amplify.Auth.signIn( + "username", + "password", + options, + { result -> + // result.signInStep === 'DONE' + handleNextSignInStep(result) + }, + { error -> + Log.e("AuthQuickstart", "Failed to sign in", error) + } +) + +// WEB_AUTHN +// sign in with preferred challenge as web authn +// no user input required at this step +val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) + .callingActivity(callingActivity) + .build() +Amplify.Auth.signIn( + "username", + null, + options, + { result -> + // result.signInStep === 'DONE' + handleNextSignInStep(result) + }, + { error -> + Log.e("AuthQuickstart", "Failed to sign in", error) + } +) + +// EMAIL_OTP +// sign in with preferred challenge as email otp +// no user input required at this step val options = AWSCognitoAuthSignInOptions.builder() .authFlowType(AuthFlowType.USER_AUTH) .preferredFirstFactor(AuthFactorType.EMAIL_OTP) .callingActivity(callingActivity) .build() +Amplify.Auth.signIn( + "username", + null, + options, + { result -> + // result.signInStep === 'CONFIRM_SIGN_IN_WITH_OTP' + handleNextSignInStep(result) + }, + { error -> + Log.e("AuthQuickstart", "Failed to sign in", error) + } +) + +// SMS_OTP +// sign in with preferred challenge as sms otp +// no user input required at this step +val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.SMS_OTP) + .callingActivity(callingActivity) + .build() +Amplify.Auth.signIn( + "username", + null, + options, + { result -> + // result.signInStep === 'CONFIRM_SIGN_IN_WITH_OTP' + handleNextSignInStep(result) + }, + { error -> + Log.e("AuthQuickstart", "Failed to sign in", error) + } +) ``` - - - + ```kotlin // PASSWORD_SRP / PASSWORD // sign in with preferred challenge as password // note password must be provided in same step -const { nextStep } = await signIn({ - username: state.username, - password: state.password, - options: { - authFlowType: "USER_AUTH", - preferredChallenge: "PASSWORD_SRP" // or "PASSWORD" - }, -}); - -// nextStep.signInStep === 'DONE' -handleNextSignInStep(nextStep); +try { + val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or AuthFactorType.PASSWORD + .callingActivity(callingActivity) + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = "password", + options = options + ) + // result.signInStep === 'DONE' + handleNextSignInStep(result) +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} // WEB_AUTHN // sign in with preferred challenge as web authn // no user input required at this step -const { nextStep } = await signIn({ - username: state.username, - options: { - authFlowType: "USER_AUTH", - preferredChallenge: "WEB_AUTHN" - }, -}); - -// nextStep.signInStep === 'DONE' -handleNextSignInStep(nextStep); +try { + val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) + .callingActivity(callingActivity) + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = null, + options = options + ) + // result.signInStep === 'DONE' + handleNextSignInStep(result) +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} // EMAIL_OTP // sign in with preferred challenge as email otp // no user input required at this step -const { nextStep } = await signIn({ - username: state.username, - options: { - authFlowType: "USER_AUTH", - preferredChallenge: "EMAIL_OTP" - }, -}); +try { + val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.EMAIL_OTP) + .callingActivity(callingActivity) + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = null, + options = options + ) + // result.signInStep === 'CONFIRM_SIGN_IN_WITH_OTP' + handleNextSignInStep(result) +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} -// nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE' -handleNextSignInStep(nextStep); +// SMS_OTP +// sign in with preferred challenge as sms otp +// no user input required at this step +try { + val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.SMS_OTP) + .callingActivity(callingActivity) + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = null, + options = options + ) + // result.signInStep === 'CONFIRM_SIGN_IN_WITH_OTP' + handleNextSignInStep(result) +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} +``` + + + +```java +// PASSWORD_SRP / PASSWORD +// sign in with preferred challenge as password +// note password must be provided in same step +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or AuthFactorType.PASSWORD + .callingActivity(callingActivity) + .build(); +RxAmplify.Auth.signIn("username", "password", options) + .subscribe( + result -> { + // result.getNextStep() === 'DONE' + handleNextSignInStep(result) + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); + +// WEB_AUTHN +// sign in with preferred challenge as web authn +// no user input required at this step +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) + .callingActivity(callingActivity) + .build(); +RxAmplify.Auth.signIn("username", null, options) + .subscribe( + result -> { + // result.getNextStep() === 'DONE' + handleNextSignInStep(result) + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); + +// EMAIL_OTP +// sign in with preferred challenge as email otp +// no user input required at this step +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.EMAIL_OTP) + .callingActivity(callingActivity) + .build(); +RxAmplify.Auth.signIn("username", null, options) + .subscribe( + result -> { + // result.getNextStep() === 'CONFIRM_SIGN_IN_WITH_OTP' + handleNextSignInStep(result) + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); // SMS_OTP // sign in with preferred challenge as sms otp // no user input required at this step -const { nextStep } = await signIn({ - username: state.username, - options: { - authFlowType: "USER_AUTH", - preferredChallenge: "SMS_OTP" - }, -}); +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.SMS_OTP) + .callingActivity(callingActivity) + .build(); +RxAmplify.Auth.signIn("username", null, options) + .subscribe( + result -> { + // result.getNextStep() === 'CONFIRM_SIGN_IN_WITH_OTP' + handleNextSignInStep(result) + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); -// nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_SMS_CODE' -handleNextSignInStep(nextStep); ``` + + + + Note that if the preferred auth factor is not available, the preference will be ignored and the flow will continue to first factor discovery. ### Passwordless Sign In with First Factor Discovery From 6f8b0262fd18e4fa807eeeef918f7cb3dffea68b Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Tue, 26 Nov 2024 14:31:10 -0800 Subject: [PATCH 03/19] Finish adding the non-webauthn sign in docs --- .../connect-your-frontend/sign-in/index.mdx | 328 +++++++++++++++++- 1 file changed, 311 insertions(+), 17 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index 70440034755..a5cb4d82397 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -1569,32 +1569,122 @@ RxAmplify.Auth.signIn("username", null, options) - Note that if the preferred auth factor is not available, the preference will be ignored and the flow will continue to first factor discovery. ### Passwordless Sign In with First Factor Discovery -When multiple first factor options are available and none are set as preferred in InitiateAuth API call (or preferred challenge is not available), Amplify JS continues to a new sign in step `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`: +When multiple first factor options are available and none are set as preferred in InitiateAuth API call (or preferred challenge is not available), Amplify Auth continues to a new sign in step `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`: -```ts -interface ContinueSignInWithFirstFactorSelection { - signInStep: 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION'; - availableChallenges?: ChallengeName[]; -} + + + +```java +// The callingActivity parameter should always be set if your app is +// expecting to use WebAuthn as not setting this option will lead to +// a sub-optimal user experience when authenticating via WebAuthn +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build(); +Amplify.Auth.signIn( + "username", + null, + options, + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { + Log.i( + "AuthQuickStart", + "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors() + ); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) +); ``` -```ts -const { nextStep } = await signIn({ - username: state.username, - options: { - authFlowType: "USER_AUTH", + + + +```kotlin +// Retrieve the authentication factors by calling .availableFactors +val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build() +Amplify.Auth.signIn( + "username", + null, + options, + { result -> + if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { + Log.i( + "AuthQuickStart", + "Available factors for this user: ${result.nextStep.availableFactors}" + ) + } + }, + { error -> + Log.e("AuthQuickstart", "Failed to sign in", error) } -}); +) +``` -// nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION' -handleNextSignInStep(nextStep); + + + +```kotlin +try { + // Retrieve the authentication factors by calling .availableFactors + val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = null, + options = options + ) + if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { + Log.i( + "AuthQuickStart", + "Available factors for this user: ${result.nextStep.availableFactors}" + ) + } +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} ``` + + + +```java +// Retrieve the authentication factors by calling .availableFactors +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build(); +RxAmplify.Auth.signIn("username", null, options) + .subscribe( + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { + Log.i( + "AuthQuickStart", + "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors() + ); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); +``` + + + + To initiate an available first factor, the desired first factor type is passed to confirm sign in as the challenge response. The next sections will that step for each `AuthFactorType`. @@ -1621,7 +1711,108 @@ handleNextSignInStep(nextStep); -{/* */} +To request an OTP code via SMS for authentication, you must pass the SMS auth factor type (`AuthFactorType.SMS_OTP`) to the `confirmSignIn` API. + +Amplify will respond appropriately to Cognito and return the challenge as the sign in next step: `CONFIRM_SIGN_IN_WITH_OTP_CODE`. You will call `confirmSignIn` again, this time with the OTP that your user provides. + + + + +```java +// First confirm the challenge type +Amplify.Auth.confirmSignIn( + AuthFactorType.SMS_OTP.name(), + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { + // Show UI to collect OTP + } + }, + error -> Log.e("AuthQuickstart", error.toString()) +); + +// Then pass that OTP into the confirmSignIn API +Amplify.Auth.confirmSignIn( + "123456", + result -> { + // result.nextStep.signInStep should be "DONE" now + }, + error -> Log.e("AuthQuickstart", error.toString()) +); +``` + + + + +```kotlin +// First confirm the challenge type +Amplify.Auth.confirmSignIn( + AuthFactorType.SMS_OTP.name, + { result -> + if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { + // Show UI to collect OTP + } + }, + { error -> + Log.i("AuthQuickstart", "Failed to sign in", error) + } +) + +// Then pass that OTP into the confirmSignIn API +Amplify.Auth.confirmSignIn( + "123456", + { result -> + // result.nextStep.signInStep should be "DONE" now + }, + { error -> + Log.i("AuthQuickstart", "Failed to sign in", error) + } +) +``` + + + + +```kotlin +// First confirm the challenge type +var result = Amplify.Auth.confirmSignIn(AuthFactorType.SMS_OTP.name) +if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { + // Show UI to collect OTP +} + +// Then pass that OTP into the confirmSignIn API +result = Amplify.Auth.confirmSignIn("123456") + +// result.nextStep.signInStep should be "DONE" now +``` + + + + +```java +// First confirm the challenge type +RxAmplify.Auth.confirmSignIn(AuthFactorType.SMS_OTP.name()) + .subscribe( + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { + // Show UI to collect OTP + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); + +// Then pass that OTP into the confirmSignIn API +RxAmplify.Auth.confirmSignIn("123456") + .subscribe( + result -> { + // result.nextStep.signInStep should be "DONE" now + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); +``` + + + + @@ -1724,7 +1915,110 @@ handleNextSignInStep(nextStep); -{/* */} + +To request an OTP code via email for authentication, you must pass the email auth factor type (`AuthFactorType.EMAIL_OTP`) to the `confirmSignIn` API. + +Amplify will respond appropriately to Cognito and return the challenge as the sign in next step: `CONFIRM_SIGN_IN_WITH_OTP_CODE`. You will call `confirmSignIn` again, this time with the OTP that your user provides. + + + + +```java +// First confirm the challenge type +Amplify.Auth.confirmSignIn( + AuthFactorType.EMAIL_OTP.name(), + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { + // Show UI to collect OTP + } + }, + error -> Log.e("AuthQuickstart", error.toString()) +); + +// Then pass that OTP into the confirmSignIn API +Amplify.Auth.confirmSignIn( + "123456", + result -> { + // result.nextStep.signInStep should be "DONE" now + }, + error -> Log.e("AuthQuickstart", error.toString()) +); +``` + + + + +```kotlin +// First confirm the challenge type +Amplify.Auth.confirmSignIn( + AuthFactorType.EMAIL_OTP.name, + { result -> + if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { + // Show UI to collect OTP + } + }, + { error -> + Log.i("AuthQuickstart", "Failed to sign in", error) + } +) + +// Then pass that OTP into the confirmSignIn API +Amplify.Auth.confirmSignIn( + "123456", + { result -> + // result.nextStep.signInStep should be "DONE" now + }, + { error -> + Log.i("AuthQuickstart", "Failed to sign in", error) + } +) +``` + + + + +```kotlin +// First confirm the challenge type +var result = Amplify.Auth.confirmSignIn(AuthFactorType.EMAIL_OTP.name) +if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { + // Show UI to collect OTP +} + +// Then pass that OTP into the confirmSignIn API +result = Amplify.Auth.confirmSignIn("123456") + +// result.nextStep.signInStep should be "DONE" now +``` + + + + +```java +// First confirm the challenge type +RxAmplify.Auth.confirmSignIn(AuthFactorType.EMAIL_OTP.name()) + .subscribe( + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { + // Show UI to collect OTP + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); + +// Then pass that OTP into the confirmSignIn API +RxAmplify.Auth.confirmSignIn("123456") + .subscribe( + result -> { + // result.nextStep.signInStep should be "DONE" now + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); +``` + + + + + From 6df81f10c5e0666415c6248e28fb1bd37de70466 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Tue, 26 Nov 2024 15:02:19 -0800 Subject: [PATCH 04/19] Add passwordless sign in docs into the multi-step-sign-in page --- .../multi-step-sign-in/index.mdx | 234 ++++++++++-------- .../connect-your-frontend/sign-in/index.mdx | 16 +- 2 files changed, 143 insertions(+), 107 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx index 4604f7441da..9aae5c63efe 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx @@ -1067,102 +1067,113 @@ The `nextStep` property is of enum type `AuthSignInStep`. Depending on its value ```java try { - AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder().authFlowType(AuthFlowType.USER_SRP_AUTH).build(); - Amplify.Auth.signIn( - "username", - "password", - options, - result -> - { - AuthNextSignInStep nextStep = result.getNextStep(); - switch (nextStep.getSignInStep()) { - case CONFIRM_SIGN_IN_WITH_TOTP_CODE: { - Log.i("AuthQuickstart", "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 - break; - } - case CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION: { - Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); - Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); - // Prompt the user to select the MFA type they want to setup - // Then invoke `confirmSignIn` api with the MFA type - break; - } - case CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP: { - Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); - // Prompt the user to enter the email address they would like to use to receive OTPs - // Then invoke `confirmSignIn` api with the email address - break; - } - case CONTINUE_SIGN_IN_WITH_TOTP_SETUP: { - Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP"); - Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app" + nextStep.getTotpSetupDetails().getSharedSecret()); - // Prompt the user to enter the TOTP code generated in their authenticator app - // Then invoke `confirmSignIn` api with the code - break; - } - case CONTINUE_SIGN_IN_WITH_MFA_SELECTION: { - Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type"); - Log.i("AuthQuickstart", "Allowed MFA type" + nextStep.getAllowedMFATypes()); - // Prompt the user to select the MFA type they want to use - // Then invoke `confirmSignIn` api with the MFA type - break; - } - case CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE: { - Log.i("AuthQuickstart", "SMS code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); - Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); - // Prompt the user to enter the SMS MFA code they received - // Then invoke `confirmSignIn` api with the code - break; - } - case CONFIRM_SIGN_IN_WITH_OTP: { - Log.i("AuthQuickstart", "OTP code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); - Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); - // Prompt the user to enter the OTP MFA code they received - // Then invoke `confirmSignIn` api with the code - break; - } - case CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE: { - Log.i("AuthQuickstart", "Custom challenge, additional info: " + nextStep.getAdditionalInfo()); - // Prompt the user to enter custom challenge answer - // Then invoke `confirmSignIn` api with the answer - break; - } - case CONFIRM_SIGN_IN_WITH_NEW_PASSWORD: { - Log.i("AuthQuickstart", "Sign in with new password, additional info: " + nextStep.getAdditionalInfo()); - // Prompt the user to enter a new password - // Then invoke `confirmSignIn` api with new password - break; - } - case DONE: { - Log.i("AuthQuickstart", "SignIn complete"); - // User has successfully signed in to the app - break; - } - } - }, - error -> { - if (error instanceof UserNotConfirmedException) { - // 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. - Log.i("AuthQuickstart", "Signup confirmation required" + error); - } else if (error instanceof PasswordResetRequiredException) { - // 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. - Log.i("AuthQuickstart", "Password reset required" + error); - } else { - Log.e("AuthQuickstart", "SignIn failed: " + error); - } - } - - ); + AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder().authFlowType(AuthFlowType.USER_SRP_AUTH).build(); + Amplify.Auth.signIn( + "username", + "password", + options, + result -> + { + AuthNextSignInStep nextStep = result.getNextStep(); + switch (nextStep.getSignInStep()) { + case CONFIRM_SIGN_IN_WITH_TOTP_CODE: { + Log.i("AuthQuickstart", "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 + break; + } + case CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION: { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); + Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); + // Prompt the user to select the MFA type they want to setup + // Then invoke `confirmSignIn` api with the MFA type + break; + } + case CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP: { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); + // Prompt the user to enter the email address they would like to use to receive OTPs + // Then invoke `confirmSignIn` api with the email address + break; + } + case CONTINUE_SIGN_IN_WITH_TOTP_SETUP: { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP"); + Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app" + nextStep.getTotpSetupDetails().getSharedSecret()); + // Prompt the user to enter the TOTP code generated in their authenticator app + // Then invoke `confirmSignIn` api with the code + break; + } + case CONTINUE_SIGN_IN_WITH_MFA_SELECTION: { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type"); + Log.i("AuthQuickstart", "Allowed MFA type" + nextStep.getAllowedMFATypes()); + // Prompt the user to select the MFA type they want to use + // Then invoke `confirmSignIn` api with the MFA type + break; + } + case CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION: { + Log.i("AuthQuickstart", "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors()); + // Prompt the user to select which authentication factor they want to use to sign-in + // Then invoke `confirmSignIn` api with that selection + break; + } + case CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE: { + Log.i("AuthQuickstart", "SMS code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); + Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); + // Prompt the user to enter the SMS MFA code they received + // Then invoke `confirmSignIn` api with the code + break; + } + case CONFIRM_SIGN_IN_WITH_OTP: { + Log.i("AuthQuickstart", "OTP code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); + Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); + // Prompt the user to enter the OTP MFA code they received + // Then invoke `confirmSignIn` api with the code + break; + } + case CONFIRM_SIGN_IN_WITH_PASSWORD: { + Log.i("AuthQuickstart", "Received next step as confirm sign in with password"); + // Prompt the user to enter their password + // Then invoke `confirmSignIn` api with that password + break; + } + case CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE: { + Log.i("AuthQuickstart", "Custom challenge, additional info: " + nextStep.getAdditionalInfo()); + // Prompt the user to enter custom challenge answer + // Then invoke `confirmSignIn` api with the answer + break; + } + case CONFIRM_SIGN_IN_WITH_NEW_PASSWORD: { + Log.i("AuthQuickstart", "Sign in with new password, additional info: " + nextStep.getAdditionalInfo()); + // Prompt the user to enter a new password + // Then invoke `confirmSignIn` api with new password + break; + } + case DONE: { + Log.i("AuthQuickstart", "SignIn complete"); + // User has successfully signed in to the app + break; + } + } + }, + error -> { + if (error instanceof UserNotConfirmedException) { + // 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. + Log.i("AuthQuickstart", "Signup confirmation required" + error); + } else if (error instanceof PasswordResetRequiredException) { + // 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. + Log.i("AuthQuickstart", "Password reset required" + error); + } else { + Log.e("AuthQuickstart", "SignIn failed: " + error); + } + } + ); } catch (Exception error) { Log.e("AuthQuickstart", "Unexpected error occurred: " + error); } @@ -1465,7 +1476,11 @@ RxAmplify.Auth.signIn("username", "password", options).subscribe( If the next step is `CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE`, Amplify Auth has sent the user a random code over SMS, and is waiting to find out if the user successfully received it. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API. -Note: the signIn result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial phone number of the SMS recipient. + + +The result result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial phone number of the SMS recipient. + + @@ -1572,7 +1587,21 @@ After the user enters the code, your implementation must pass the value to Ampli If the next step is `CONFIRM_SIGN_IN_WITH_EMAIL_MFA_CODE`, Amplify Auth has sent the user a random code to their email address and is waiting to find out if the user successfully received it. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API. -Note: the signIn result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial email address of the recipient. + + +The result result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial email address of the recipient. + + + +## Confirm sign-in with OTP + +If the next step is `CONFIRM_SIGN_IN_WITH_OTP`, Amplify Auth has sent the user a random code to the medium of the user's choosing (e.g. SMS or email) and is waiting for the user to verify that code. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, pass the value to the `confirmSignIn` API. + + + +The result includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery, such as the partial email address of the recipient, which can be used to prompt the user on where to look for the code. + + ## Continue sign-in with MFA Selection @@ -1592,6 +1621,10 @@ Once the authenticator app is set up, the user can generate a TOTP code and prov If the next step is `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION`, the user must select the MFA method to setup. Amplify Auth currently supports SMS, TOTP, and email as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. +## Continue sign-in with First Factor Selection + +If the next step is `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`, the user must select an authentication factor to use either because they did not specify one or because the one they chose is not supported (e.g. selecting SMS when they don't have a phone number registered to their account). Amplify Auth currently supports SMS, email, password, and webauthn as authentication factors. After the user selects an authentication method, your implementation must pass the selected authentication method to Amplify Auth using `confirmSignIn` API. + ## Confirm sign-in with custom challenge If the next step is `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE`, Amplify Auth is awaiting completion of a custom authentication challenge. The challenge is based on the Lambda trigger you setup when you configured a [custom sign in flow](/[platform]/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/#sign-in-a-user). To complete this step, you should prompt the user for the custom challenge answer, and pass the answer to the `confirmSignIn` API. @@ -1933,7 +1966,10 @@ RxAmplify.Auth.confirmSignUp( This call fetches the current logged in user and should be used after a user has been successfully signed in. If the user is signed in, it will return the current userId and username. -Note: An empty string will be assigned to userId and/or username, if the values are not present in the accessToken. + + +An empty string will be assigned to userId and/or username, if the values are not present in the accessToken. + diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index a5cb4d82397..a147376e9e4 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -1141,7 +1141,7 @@ Amplify.Auth.signIn( "username", null, options, - result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()), + result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), error -> Log.e("AuthQuickstart", error.toString()) ); ``` @@ -1162,7 +1162,7 @@ Amplify.Auth.signIn( null, options, { result -> - Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") + Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}") }, { error -> Log.e("AuthQuickstart", "Failed to sign in", error) @@ -1187,7 +1187,7 @@ try { password = null, options = options ) - Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") + Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}") } catch (error: AuthException) { Log.e("AuthQuickstart", "Sign in failed", error) } @@ -1208,7 +1208,7 @@ AWSCognitoAuthSignInOptions options = .build(); RxAmplify.Auth.signIn("username", null, options) .subscribe( - result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()), + result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), error -> Log.e("AuthQuickstart", error.toString()) ); ``` @@ -1595,7 +1595,7 @@ Amplify.Auth.signIn( result -> { if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { Log.i( - "AuthQuickStart", + "AuthQuickstart", "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors() ); } @@ -1620,7 +1620,7 @@ Amplify.Auth.signIn( { result -> if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { Log.i( - "AuthQuickStart", + "AuthQuickstart", "Available factors for this user: ${result.nextStep.availableFactors}" ) } @@ -1648,7 +1648,7 @@ try { ) if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { Log.i( - "AuthQuickStart", + "AuthQuickstart", "Available factors for this user: ${result.nextStep.availableFactors}" ) } @@ -1673,7 +1673,7 @@ RxAmplify.Auth.signIn("username", null, options) result -> { if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { Log.i( - "AuthQuickStart", + "AuthQuickstart", "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors() ); } From f6827c3e902b29948811cfc3bfb0745cd2bc7611 Mon Sep 17 00:00:00 2001 From: Matt Creaser Date: Wed, 27 Nov 2024 11:58:12 -0400 Subject: [PATCH 05/19] Update manage-webauthn-credentials/index.mdx for android --- .../manage-webauthn-credentials/index.mdx | 116 +++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/src/pages/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/index.mdx b/src/pages/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/index.mdx index 1f31f20593b..c82e8c02160 100644 --- a/src/pages/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/index.mdx @@ -55,7 +55,51 @@ await associateWebAuthnCredential(); -{/* */} + + + +```java +Amplify.Auth.associateWebAuthnCredential( + () -> Log.i("AuthQuickstart", "Associated credential"), + error -> Log.e("AuthQuickstart", "Failed to register credential", error) +); +``` + + + + +```kotlin +Amplify.Auth.associateWebAuthnCredential( + { Log.i("AuthQuickstart", "Associated credential") }, + { Log.e("AuthQuickstart", "Failed to register credential", error) } +) +``` + + + + +```kotlin +try { + val result = Amplify.Auth.associateWebAuthnCredential() + Log.i("AuthQuickstart", "Associated credential") +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Failed to associate credential", error) +} +``` + + + + +```java +RxAmplify.Auth.associateWebAuthnCredential() + .subscribe( + result -> Log.i("AuthQuickstart", "Associated credential"), + error -> Log.e("AuthQuickstart", "Failed to associate credential", error) + ); +``` + + + @@ -186,6 +230,76 @@ func listWebAuthNCredentials() -> AnyCancellable { + + + + + + +```java +Amplify.Auth.listWebAuthnCredentials( + result -> result.getCredentials().forEach(credential -> { + Log.i("AuthQuickstart", "Credential ID: " + credential.getCredentialId()); + Log.i("AuthQuickstart", "Friendly Name: " + credential.getFriendlyName()); + Log.i("AuthQuickstart", "Relying Party ID: " + credential.getRelyingPartyId()); + Log.i("AuthQuickstart", "Created At: " + credential.getCreatedAt()); + }), + error -> Log.e("AuthQuickstart", "Failed to list credentials", error) +); +``` + + + + +```kotlin +Amplify.Auth.listWebAuthnCredentials( + { result -> + result.credentials.forEach { credential -> + Log.i("AuthQuickstart", "Credential ID: ${credential.credentialId}") + Log.i("AuthQuickstart", "Friendly Name: ${credential.friendlyName}") + Log.i("AuthQuickstart", "Relying Party ID: ${credential.relyingPartyId}") + Log.i("AuthQuickstart", "Created At: ${credential.createdAt}") + } + }, + { error -> Log.e("AuthQuickstart", "Failed to list credentials", error) } +) +``` + + + + +```kotlin +try { + val result = Amplify.Auth.listWebAuthnCredentials() + result.credentials.forEach { credential -> + Log.i("AuthQuickstart", "Credential ID: ${credential.credentialId}") + Log.i("AuthQuickstart", "Friendly Name: ${credential.friendlyName}") + Log.i("AuthQuickstart", "Relying Party ID: ${credential.relyingPartyId}") + Log.i("AuthQuickstart", "Created At: ${credential.createdAt}") + } +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Failed to list credentials", error) +} +``` + + + + +```java +RxAmplify.Auth.listWebAuthnCredentials() + .subscribe( + result -> result.getCredentials().forEach(credential -> { + Log.i("AuthQuickstart", "Credential ID: " + credential.getCredentialId()); + Log.i("AuthQuickstart", "Friendly Name: " + credential.getFriendlyName()); + Log.i("AuthQuickstart", "Relying Party ID: " + credential.getRelyingPartyId()); + Log.i("AuthQuickstart", "Created At: " + credential.getCreatedAt()); + }), + error -> Log.e("AuthQuickstart", "Failed to list credentials", error) + ); +``` + + + ## Delete WebAuthN credentials From c75d2eb8c84507146ace583c63f64f16f4ee8f1d Mon Sep 17 00:00:00 2001 From: Matt Creaser Date: Wed, 27 Nov 2024 12:53:29 -0400 Subject: [PATCH 06/19] Add callingActivity to associateWebAuthnCredential examples --- .../manage-webauthn-credentials/index.mdx | 75 +++++++++++++++---- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/index.mdx b/src/pages/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/index.mdx index c82e8c02160..af358d68c50 100644 --- a/src/pages/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/index.mdx @@ -60,6 +60,7 @@ await associateWebAuthnCredential(); ```java Amplify.Auth.associateWebAuthnCredential( + activity, () -> Log.i("AuthQuickstart", "Associated credential"), error -> Log.e("AuthQuickstart", "Failed to register credential", error) ); @@ -70,6 +71,7 @@ Amplify.Auth.associateWebAuthnCredential( ```kotlin Amplify.Auth.associateWebAuthnCredential( + activity, { Log.i("AuthQuickstart", "Associated credential") }, { Log.e("AuthQuickstart", "Failed to register credential", error) } ) @@ -80,7 +82,7 @@ Amplify.Auth.associateWebAuthnCredential( ```kotlin try { - val result = Amplify.Auth.associateWebAuthnCredential() + val result = Amplify.Auth.associateWebAuthnCredential(activity) Log.i("AuthQuickstart", "Associated credential") } catch (error: AuthException) { Log.e("AuthQuickstart", "Failed to associate credential", error) @@ -91,7 +93,7 @@ try { ```java -RxAmplify.Auth.associateWebAuthnCredential() +RxAmplify.Auth.associateWebAuthnCredential(activity) .subscribe( result -> Log.i("AuthQuickstart", "Associated credential"), error -> Log.e("AuthQuickstart", "Failed to associate credential", error) @@ -101,6 +103,8 @@ RxAmplify.Auth.associateWebAuthnCredential() +You must supply an `Activity` instance so that Amplify can display the PassKey UI in your Application's [Task](https://developer.android.com/guide/components/activities/tasks-and-back-stack). + @@ -138,8 +142,8 @@ func associateWebAuthNCredentials() -> AnyCancellable { - -You will be prompted to register a passkey using your local authenticator. Amplify will then associate that passkey with Cognito. + +The user will be prompted to register a passkey using their local authenticator. Amplify will then associate that passkey with Cognito. ## List WebAuthN credentials @@ -160,11 +164,6 @@ for (const credential of result.credentials) { } ``` - - - -{/* */} - @@ -317,11 +316,6 @@ await deleteWebAuthnCredential({ credentialId: id }); ``` - - - -{/* */} - @@ -358,6 +352,59 @@ func deleteWebAuthNCredentials(credentialId: String) -> AnyCancellable { + + + + + +```java +Amplify.Auth.deleteWebAuthnCredential( + credentialId, + (result) -> Log.i("AuthQuickstart", "Deleted credential"), + error -> Log.e("AuthQuickstart", "Failed to delete credential", error) +); +``` + + + + +```kotlin +Amplify.Auth.deleteWebAuthnCredential( + credentialId, + { Log.i("AuthQuickstart", "Deleted credential") }, + { Log.e("AuthQuickstart", "Failed to delete credential", error) } +) +``` + + + + +```kotlin +try { + val result = Amplify.Auth.deleteWebAuthnCredential(credentialId) + Log.i("AuthQuickstart", "Deleted credential") +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Failed to delete credential", error) +} +``` + + + + +```java +RxAmplify.Auth.deleteWebAuthnCredential(credentialId) + .subscribe( + result -> Log.i("AuthQuickstart", "Deleted credential"), + error -> Log.e("AuthQuickstart", "Failed to delete credential", error) + ); +``` + + + + +The delete passkey API has only the required `credentialId` as input, and it does not return a value. + + From 01de686829b80f49dc627b37a8ad112737ba767e Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Wed, 27 Nov 2024 09:16:33 -0800 Subject: [PATCH 07/19] Bring android sign-in docs to parity --- .../connect-your-frontend/sign-in/index.mdx | 612 ++---------------- 1 file changed, 38 insertions(+), 574 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index a147376e9e4..6f1e34b5198 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -1111,584 +1111,13 @@ func socialSignInWithWebUI() -> AnyCancellable { - + ## Sign in with passwordless methods Your application's users can also sign in using passwordless methods. To learn more, visit the [concepts page for passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/) - - -### New auth flow type - -In order to facilitate the new passwordless sign in options, Cognito is introducing a new auth flow type known as `USER_AUTH`. This flow is designed to be flexible and supports both password and passwordless sign in factors. - - - - -```java -// The callingActivity parameter should always be set if your app is -// expecting to use WebAuthn as not setting this option will lead to -// a sub-optimal user experience when authenticating via WebAuthn -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .callingActivity(callingActivity) - .build(); -Amplify.Auth.signIn( - "username", - null, - options, - result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), - error -> Log.e("AuthQuickstart", error.toString()) -); -``` - - - - -```kotlin -// The callingActivity parameter should always be set if your app is -// expecting to use WebAuthn as not setting this option will lead to -// a sub-optimal user experience when authenticating via WebAuthn -val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .callingActivity(callingActivity) - .build() -Amplify.Auth.signIn( - "username", - null, - options, - { result -> - Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}") - }, - { error -> - Log.e("AuthQuickstart", "Failed to sign in", error) - } -) -``` - - - - -```kotlin -try { - // The callingActivity parameter should always be set if your app is - // expecting to use WebAuthn as not setting this option will lead to - // a sub-optimal user experience when authenticating via WebAuthn - val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .callingActivity(callingActivity) - .build() - val result = Amplify.Auth.signIn( - username = "username", - password = null, - options = options - ) - Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}") -} catch (error: AuthException) { - Log.e("AuthQuickstart", "Sign in failed", error) -} -``` - - - - -```java -// The callingActivity parameter should always be set if your app is -// expecting to use WebAuthn as not setting this option will lead to -// a sub-optimal user experience when authenticating via WebAuthn -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .callingActivity(callingActivity) - .build(); -RxAmplify.Auth.signIn("username", null, options) - .subscribe( - result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), - error -> Log.e("AuthQuickstart", error.toString()) - ); -``` - - - - - -### Sign In with a Preferred Challenge for First Factor - -The USER_AUTH sign in flow will support the following methods of first factor authentication: `AuthFactorType.WEB_AUTHN`, `AuthFactorType.EMAIL_OTP`, `AuthFactorType.SMS_OTP`, `AuthFactorType.PASSWORD`, and `AuthFactorType.PASSWORD_SRP`. - -If the desired first factor is known before the sign in flow is initiated it can be passed to the initial sign in call: - - - - -```java -// PASSWORD_SRP / PASSWORD -// sign in with preferred challenge as password -// note password must be provided in same step -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or AuthFactorType.PASSWORD - .callingActivity(callingActivity) - .build(); -Amplify.Auth.signIn( - "username", - "password", - options, - result -> { - // result.getNextStep() === 'DONE' - handleNextSignInStep(result); - }, - error -> Log.e("AuthQuickstart", "Failed to sign in", error) -); - -// WEB_AUTHN -// sign in with preferred challenge as web authn -// no user input required at this step -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.WEB_AUTHN) - .callingActivity(callingActivity) - .build(); -Amplify.Auth.signIn( - "username", - null, - options, - result -> { - // result.getNextStep() === 'DONE' - handleNextSignInStep(result); - }, - error -> Log.e("AuthQuickstart", "Failed to sign in", error) -); - -// EMAIL_OTP -// sign in with preferred challenge as email otp -// no user input required at this step -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.EMAIL_OTP) - .callingActivity(callingActivity) - .build(); -Amplify.Auth.signIn( - "username", - null, - options, - result -> { - // result.getNextStep() === 'CONFIRM_SIGN_IN_WITH_OTP' - handleNextSignInStep(result); - }, - error -> Log.e("AuthQuickstart", "Failed to sign in", error) -); - -// SMS_OTP -// sign in with preferred challenge as sms otp -// no user input required at this step -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.SMS_OTP) - .callingActivity(callingActivity) - .build(); -Amplify.Auth.signIn( - "username", - null, - options, - result -> { - // result.getNextStep() === 'CONFIRM_SIGN_IN_WITH_OTP' - handleNextSignInStep(result); - }, - error -> Log.e("AuthQuickstart", "Failed to sign in", error) -); -``` - - - - -```kotlin -// PASSWORD_SRP / PASSWORD -// sign in with preferred challenge as password -// note password must be provided in same step -val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or AuthFactorType.PASSWORD - .callingActivity(callingActivity) - .build() -Amplify.Auth.signIn( - "username", - "password", - options, - { result -> - // result.signInStep === 'DONE' - handleNextSignInStep(result) - }, - { error -> - Log.e("AuthQuickstart", "Failed to sign in", error) - } -) - -// WEB_AUTHN -// sign in with preferred challenge as web authn -// no user input required at this step -val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.WEB_AUTHN) - .callingActivity(callingActivity) - .build() -Amplify.Auth.signIn( - "username", - null, - options, - { result -> - // result.signInStep === 'DONE' - handleNextSignInStep(result) - }, - { error -> - Log.e("AuthQuickstart", "Failed to sign in", error) - } -) - -// EMAIL_OTP -// sign in with preferred challenge as email otp -// no user input required at this step -val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.EMAIL_OTP) - .callingActivity(callingActivity) - .build() -Amplify.Auth.signIn( - "username", - null, - options, - { result -> - // result.signInStep === 'CONFIRM_SIGN_IN_WITH_OTP' - handleNextSignInStep(result) - }, - { error -> - Log.e("AuthQuickstart", "Failed to sign in", error) - } -) - -// SMS_OTP -// sign in with preferred challenge as sms otp -// no user input required at this step -val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.SMS_OTP) - .callingActivity(callingActivity) - .build() -Amplify.Auth.signIn( - "username", - null, - options, - { result -> - // result.signInStep === 'CONFIRM_SIGN_IN_WITH_OTP' - handleNextSignInStep(result) - }, - { error -> - Log.e("AuthQuickstart", "Failed to sign in", error) - } -) -``` - - - -```kotlin -// PASSWORD_SRP / PASSWORD -// sign in with preferred challenge as password -// note password must be provided in same step -try { - val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or AuthFactorType.PASSWORD - .callingActivity(callingActivity) - .build() - val result = Amplify.Auth.signIn( - username = "username", - password = "password", - options = options - ) - // result.signInStep === 'DONE' - handleNextSignInStep(result) -} catch (error: AuthException) { - Log.e("AuthQuickstart", "Sign in failed", error) -} - -// WEB_AUTHN -// sign in with preferred challenge as web authn -// no user input required at this step -try { - val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.WEB_AUTHN) - .callingActivity(callingActivity) - .build() - val result = Amplify.Auth.signIn( - username = "username", - password = null, - options = options - ) - // result.signInStep === 'DONE' - handleNextSignInStep(result) -} catch (error: AuthException) { - Log.e("AuthQuickstart", "Sign in failed", error) -} - -// EMAIL_OTP -// sign in with preferred challenge as email otp -// no user input required at this step -try { - val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.EMAIL_OTP) - .callingActivity(callingActivity) - .build() - val result = Amplify.Auth.signIn( - username = "username", - password = null, - options = options - ) - // result.signInStep === 'CONFIRM_SIGN_IN_WITH_OTP' - handleNextSignInStep(result) -} catch (error: AuthException) { - Log.e("AuthQuickstart", "Sign in failed", error) -} - -// SMS_OTP -// sign in with preferred challenge as sms otp -// no user input required at this step -try { - val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.SMS_OTP) - .callingActivity(callingActivity) - .build() - val result = Amplify.Auth.signIn( - username = "username", - password = null, - options = options - ) - // result.signInStep === 'CONFIRM_SIGN_IN_WITH_OTP' - handleNextSignInStep(result) -} catch (error: AuthException) { - Log.e("AuthQuickstart", "Sign in failed", error) -} -``` - - - -```java -// PASSWORD_SRP / PASSWORD -// sign in with preferred challenge as password -// note password must be provided in same step -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or AuthFactorType.PASSWORD - .callingActivity(callingActivity) - .build(); -RxAmplify.Auth.signIn("username", "password", options) - .subscribe( - result -> { - // result.getNextStep() === 'DONE' - handleNextSignInStep(result) - }, - error -> Log.e("AuthQuickstart", error.toString()) - ); - -// WEB_AUTHN -// sign in with preferred challenge as web authn -// no user input required at this step -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.WEB_AUTHN) - .callingActivity(callingActivity) - .build(); -RxAmplify.Auth.signIn("username", null, options) - .subscribe( - result -> { - // result.getNextStep() === 'DONE' - handleNextSignInStep(result) - }, - error -> Log.e("AuthQuickstart", error.toString()) - ); - -// EMAIL_OTP -// sign in with preferred challenge as email otp -// no user input required at this step -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.EMAIL_OTP) - .callingActivity(callingActivity) - .build(); -RxAmplify.Auth.signIn("username", null, options) - .subscribe( - result -> { - // result.getNextStep() === 'CONFIRM_SIGN_IN_WITH_OTP' - handleNextSignInStep(result) - }, - error -> Log.e("AuthQuickstart", error.toString()) - ); - -// SMS_OTP -// sign in with preferred challenge as sms otp -// no user input required at this step -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.SMS_OTP) - .callingActivity(callingActivity) - .build(); -RxAmplify.Auth.signIn("username", null, options) - .subscribe( - result -> { - // result.getNextStep() === 'CONFIRM_SIGN_IN_WITH_OTP' - handleNextSignInStep(result) - }, - error -> Log.e("AuthQuickstart", error.toString()) - ); - -``` - - - - -Note that if the preferred auth factor is not available, the preference will be ignored and the flow will continue to first factor discovery. - -### Passwordless Sign In with First Factor Discovery - -When multiple first factor options are available and none are set as preferred in InitiateAuth API call (or preferred challenge is not available), Amplify Auth continues to a new sign in step `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`: - - - - -```java -// The callingActivity parameter should always be set if your app is -// expecting to use WebAuthn as not setting this option will lead to -// a sub-optimal user experience when authenticating via WebAuthn -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .callingActivity(callingActivity) - .build(); -Amplify.Auth.signIn( - "username", - null, - options, - result -> { - if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { - Log.i( - "AuthQuickstart", - "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors() - ); - } - }, - error -> Log.e("AuthQuickstart", error.toString()) -); -``` - - - - -```kotlin -// Retrieve the authentication factors by calling .availableFactors -val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .callingActivity(callingActivity) - .build() -Amplify.Auth.signIn( - "username", - null, - options, - { result -> - if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { - Log.i( - "AuthQuickstart", - "Available factors for this user: ${result.nextStep.availableFactors}" - ) - } - }, - { error -> - Log.e("AuthQuickstart", "Failed to sign in", error) - } -) -``` - - - - -```kotlin -try { - // Retrieve the authentication factors by calling .availableFactors - val options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_AUTH) - .callingActivity(callingActivity) - .build() - val result = Amplify.Auth.signIn( - username = "username", - password = null, - options = options - ) - if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { - Log.i( - "AuthQuickstart", - "Available factors for this user: ${result.nextStep.availableFactors}" - ) - } -} catch (error: AuthException) { - Log.e("AuthQuickstart", "Sign in failed", error) -} -``` - - - - -```java -// Retrieve the authentication factors by calling .availableFactors -AWSCognitoAuthSignInOptions options = - AWSCognitoAuthSignInOptions - .builder() - .authFlowType(AuthFlowType.USER_AUTH) - .callingActivity(callingActivity) - .build(); -RxAmplify.Auth.signIn("username", null, options) - .subscribe( - result -> { - if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { - Log.i( - "AuthQuickstart", - "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors() - ); - } - }, - error -> Log.e("AuthQuickstart", error.toString()) - ); -``` - - - - -To initiate an available first factor, the desired first factor type is passed to confirm sign in as the challenge response. The next sections will that step for each `AuthFactorType`. - - - ### SMS OTP {/* blurb with supplemental information about handling sign-in, events, etc. */} @@ -1915,7 +1344,6 @@ handleNextSignInStep(nextStep); - To request an OTP code via email for authentication, you must pass the email auth factor type (`AuthFactorType.EMAIL_OTP`) to the `confirmSignIn` API. Amplify will respond appropriately to Cognito and return the challenge as the sign in next step: `CONFIRM_SIGN_IN_WITH_OTP_CODE`. You will call `confirmSignIn` again, this time with the OTP that your user provides. @@ -2133,12 +1561,15 @@ handleNextSignInStep(nextStep); - + ### Password or SRP Traditional password based authentication is available from this flow as well. To initiate this flow from select challenge, either `PASSWORD` or `PASSWORD_SRP` is passed as the challenge response. + + + ```ts const { nextStep } = await confirmSignIn({ challengeResponse: "PASSWORD_SRP", // or "PASSWORD" @@ -2155,6 +1586,39 @@ const { nextStep: nextNextStep } = await confirmSignIn({ // nextNextStep.signInStep === 'DONE' handleNextSignInStep(nextNextStep); ``` + + + + + + +```java +// Java code +``` + + + + +```kotlin +// Kotlin code +``` + + + + +```kotlin +// Kotlin coroutines code +``` + + + + +```java +// RxJava code +``` + + + From 5cad412495620ea862dca6ed8c5eb41b7a937622 Mon Sep 17 00:00:00 2001 From: Matt Creaser Date: Wed, 27 Nov 2024 13:57:58 -0400 Subject: [PATCH 08/19] Add Android docs for switching authentication flows --- .../switching-authentication-flows/index.mdx | 386 +++++++++++++++++- 1 file changed, 384 insertions(+), 2 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index 5c82f2da750..6fd4b05283e 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -10,7 +10,8 @@ export const meta = { 'react', 'react-native', 'swift', - 'vue' + 'vue', + 'android' ] }; @@ -28,7 +29,7 @@ export function getStaticProps() { -`AWSCognitoAuthPlugin` allows you to switch between different auth flows while initiating signIn. You can configure the flow in the `amplifyconfiguration.json` file or pass the `authFlowType` as a runtime parameter to the `signIn` api call. +`AWSCognitoAuthPlugin` allows you to switch between different auth flows while initiating signIn. You can configure the flow in the `amplify_outputs.json` file or pass the `authFlowType` as a runtime parameter to the `signIn` api call. For client side authentication there are four different flows that can be configured during runtime: @@ -274,6 +275,387 @@ To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify G + + +`AWSCognitoAuthPlugin` allows you to switch between different auth flows while initiating signIn. You can configure the flow in the `amplify_outputs.json` file or pass the `authFlowType` as a option to the `signIn` api call. + +For client side authentication there are four different flows that can be configured during runtime: + +1. `USER_SRP_AUTH`: The `USER_SRP_AUTH` flow uses the [SRP protocol (Secure Remote Password)](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol) where the password never leaves the client and is unknown to the server. This is the recommended flow and is used by default. + +2. `USER_PASSWORD_AUTH`: The `USER_PASSWORD_AUTH` flow will send user credentials unencrypted to the back-end. If you want to migrate users to Cognito using the "Migration" trigger and avoid forcing users to reset their passwords, you will need to use this authentication type because the Lambda function invoked by the trigger needs to verify the supplied credentials. + +3. `CUSTOM_AUTH_WITH_SRP`: The `CUSTOM_AUTH_WITH_SRP` flow is used to start with SRP authentication and then switch to custom authentication. This is useful if you want to use SRP for the initial authentication and then use custom authentication for subsequent authentication attempts. + +4. `CUSTOM_AUTH_WITHOUT_SRP`: The `CUSTOM_AUTH_WITHOUT_SRP` flow is used to start authentication flow **WITHOUT** SRP and then use a series of challenge and response cycles that can be customized to meet different requirements. + +5. `USER_AUTH`: The `USER_AUTH` flow is a choice-based authentication flow that allows the user to choose from the list of available authentication methods. This flow is useful when you want to provide the user with the option to choose the authentication method. The choices that may be available to the user are `EMAIL_OTP`, `SMS_OTP`, `WEB_AUTHN`, `PASSWORD` or `PASSWORD_SRP`. + +`Auth` can be configured to use the different flows at runtime by calling `signIn` with `AWSCognitoAuthSignInOptions`'s `authFlowType` as `AuthFlowType.USER_PASSWORD_AUTH`, `AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP`, `AuthFlowType.CUSTOM_AUTH_WITH_SRP`, or `AuthFlowType.USER_AUTH`. If you do not specify the `AuthFlowType` in `AWSCognitoAuthSignInOptions`, the default flow specified in `amplify_outputs.json` will be used. + + + +Runtime configuration will take precedence and will override any auth flow type configuration present in `amplify_outputs.json`. + + + +> For more information about authentication flows, please visit [Amazon Cognito developer documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow) + +## USER_AUTH (Choice-based authentication) flow + +A use case for the `USER_AUTH` authentication flow is to provide the user with the option to choose the authentication method. The choices that may be available to the user are `EMAIL_OTP`, `SMS_OTP`, `WEB_AUTHN`, `PASSWORD` or `PASSWORD_SRP`. + + +Amplify requires an `Activity` reference to attach the PassKey UI to your Application's [Task](https://developer.android.com/guide/components/activities/tasks-and-back-stack) when using WebAuthn - if an `Activity` is not supplied then the UI will appear in a separate Task. For this reason, we strongly recommend passing the `callingActivity` option to both the `signIn` and `confirmSignIn` APIs if your application uses the `USER_AUTH` flow. + + +If the desired first factor is known before the sign in flow is initiated it can be passed to the initial sign in call. + + + + +```java +// PASSWORD_SRP / PASSWORD +// Sign in with preferred challenge as password +// NOTE: Password must be provided in the same step +AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD" + .build(); +Amplify.Auth.signIn( + username, + password, + options, + result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()), + error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error) +); + +// WEB_AUTHN / EMAIL_OTP / SMS_OTP +// Sign in with preferred passwordless challenge +// No user input is required at this step +AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP" + .build(); +Amplify.Auth.signIn( + username, + null, + options, + result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()), + error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error) +); +``` + + + + +```kotlin +// PASSWORD_SRP / PASSWORD +// Sign in with preferred challenge as password +// NOTE: Password must be provided in the same step +val options = AWSCognitoAuthSignInOptions.builder() + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD" + .build() +Amplify.Auth.signIn( + username, + password, + options, + { result -> Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") }, + { error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error) } +) + +// WEB_AUTHN / EMAIL_OTP / SMS_OTP +// Sign in with preferred passwordless challenge +// No user input is required at this step +val options = AWSCognitoAuthSignInOptions.builder() + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP" + .build() +Amplify.Auth.signIn( + username, + null, + options, + { result -> Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") }, + { error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error) } +) +``` + + + + +```kotlin +// PASSWORD_SRP / PASSWORD +// Sign in with preferred challenge as password +// NOTE: Password must be provided in the same step +try { + val options = AWSCognitoAuthSignInOptions.builder() + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD" + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = "password", + options = options + ) + Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}") +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} + +// WEB_AUTHN / EMAIL_OTP / SMS_OTP +// Sign in with preferred passwordless challenge +// No user input is required at this step +try { + val options = AWSCognitoAuthSignInOptions.builder() + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP" + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = null, + options = options + ) + Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}") +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} +``` + + + + +```java +// PASSWORD_SRP / PASSWORD +// Sign in with preferred challenge as password +// NOTE: Password must be provided in the same step +AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD" + .build(); +RxAmplify.Auth.signIn(username, password, options) + .subscribe( + result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), + error -> Log.e("AuthQuickstart", "Failed to confirm sign in", error)) + ); + +// WEB_AUTHN / EMAIL_OTP / SMS_OTP +// Sign in with preferred passwordless challenge +// No user input is required at this step +AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP" + .build(); +RxAmplify.Auth.signIn(username, null, options) + .subscribe( + result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), + error -> Log.e("AuthQuickstart", "Failed to confirm sign in", error)) + ); +``` + + + + +If the preferred first factor is not supplied or is unavailable, and the user has multiple factors available, the flow will continue to select an available first factor by returning an `AuthNextSignInStep.signInStep` value of `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`, and a list of `AuthNextSignInStep.availableFactors`. + +The selection of the authentication method is done by the user. The user can choose from the available factors and proceed with the selected factor. You should call the `confirmSignIn` API with the selected factor to continue the sign-in process. Following is an example if you want to proceed with the `WEB_AUTHN` factor selection: + + + + +```java +AuthConfirmSignInOptions options = AWSCognitoAuthConfirmSignInOptions.builder() + .callingActivity(activity) + .build(); +Amplify.Auth.confirmSignIn( + AuthFactorType.WEB_AUTHN.getChallengeResponse(), + options, + result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()), + error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error) +); +``` + + + + +```kotlin +val options = AWSCognitoAuthConfirmSignInOptions.builder() + .callingActivity(activity) + .build() +Amplify.Auth.confirmSignIn( + AuthFactorType.WEB_AUTHN.challengeResponse, + options, + { result -> Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") }, + { error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error) } +) +``` + + + + +```kotlin +try { + val options = AWSCognitoAuthConfirmSignInOptions.builder() + .callingActivity(activity) + .build() + val result = Amplify.Auth.confirmSignIn( + challengeResponse = AuthFactorType.WEB_AUTHN.challengeResponse, + options = options + ) + Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}") +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} +``` + + + + +```java +AuthConfirmSignInOptions options = AWSCognitoAuthConfirmSignInOptions.builder() + .callingActivity(activity) + .build(); +RxAmplify.Auth.confirmSignIn(AuthFactorType.WEB_AUTHN.getChallengeResponse(), options) + .subscribe( + result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), + error -> Log.e("AuthQuickstart", "Failed to confirm sign in", error)) + ); +``` + + + + +## USER_PASSWORD_AUTH flow + +A use case for the `USER_PASSWORD_AUTH` authentication flow is migrating users into Amazon Cognito + +A user migration Lambda trigger helps migrate users from a legacy user management system into your user pool. If you choose the USER_PASSWORD_AUTH authentication flow, users don't have to reset their passwords during user migration. This flow sends your user's password to the service over an encrypted SSL connection during authentication. + +When you have migrated all your users, switch flows to the more secure SRP flow. The SRP flow doesn't send any passwords over the network. + + + + +```java +AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) + .build(); +Amplify.Auth.signIn( + "username", + "password", + options, + result -> Log.i("AuthQuickStart", "Sign in succeeded with result " + result), + error -> Log.e("AuthQuickStart", "Failed to sign in", error) +); +``` + + + + +```kotlin +val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) + .build() +Amplify.Auth.signIn( + "username", + "password", + options, + { result -> + Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}") + }, + { error -> + Log.e("AuthQuickstart", "Failed to sign in", error) + } +) +``` + + + + +```kotlin +try { + val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = "password", + options = options + ) + Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}") +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} +``` + + + + +```java +AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) + .build(); +RxAmplify.Auth.signIn("username", "password", options) + .subscribe( + result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), + error -> Log.e("AuthQuickstart", error.toString()) + ); +``` + + + + +### Set up auth backend + +In order to use the authentication flow `USER_PASSWORD_AUTH`, your Cognito app client has to be configured to allow it. Amplify Gen 2 enables SRP auth by default. To enable USER_PASSWORD_AUTH, you can update the `backend.ts` file with the following changes: + +```ts title="amplify/backend.ts" +import { defineBackend } from '@aws-amplify/backend' +import { auth } from './auth/resource' +import { data } from './data/resource' + +const backend = defineBackend({ + auth, + data, +}); + +// highlight-start +backend.auth.resources.cfnResources.cfnUserPoolClient.explicitAuthFlows = [ + "ALLOW_USER_PASSWORD_AUTH", + "ALLOW_USER_SRP_AUTH", + "ALLOW_USER_AUTH", + "ALLOW_REFRESH_TOKEN_AUTH" +]; +// highlight-end +``` + +### Migrate users with Amazon Cognito + +Amazon Cognito provides a trigger to migrate users from your existing user directory seamlessly into Cognito. You achieve this by configuring your User Pool's "Migration" trigger which invokes a Lambda function whenever a user that does not already exist in the user pool authenticates, or resets their password. + +In short, the Lambda function will validate the user credentials against your existing user directory and return a response object containing the user attributes and status on success. An error message will be returned if an error occurs. There's documentation around [how to set up this migration flow](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html) and more detailed instructions on [how the lambda should handle request and response objects](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html#cognito-user-pools-lambda-trigger-syntax-user-migration). + +## CUSTOM_AUTH flow + +Amazon Cognito User Pools supports customizing the authentication flow to enable custom challenge types, in addition to a password in order to verify the identity of users. The custom authentication flow is a series of challenge and response cycles that can be customized to meet different requirements. These challenge types may include CAPTCHAs or dynamic challenge questions. + +To define your challenges for custom authentication flow, you need to implement three Lambda triggers for Amazon Cognito. + +The flow is initiated by calling `signIn` with `AWSCognitoAuthSignInOptions` configured with `AuthFlowType.CUSTOM_AUTH_WITH_SRP` OR `AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP`. + +Follow the instructions in [Custom Auth Sign In](/gen1/[platform]/build-a-backend/auth/sign-in-custom-flow/) to learn about how to integrate custom authentication flow in your application with the Auth APIs. + + + + For more information about working with Lambda Triggers for custom authentication challenges, please visit [Amazon Cognito Developer Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html). From 731817f00c4a27d4af58e9087060b06325fa8ded Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Wed, 27 Nov 2024 11:43:11 -0800 Subject: [PATCH 09/19] Add USER_AUTH password to the sign in docs --- .../connect-your-frontend/sign-in/index.mdx | 86 +++++++++++++++++-- 1 file changed, 77 insertions(+), 9 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index 6f1e34b5198..9695a7a8114 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -1116,7 +1116,7 @@ func socialSignInWithWebUI() -> AnyCancellable { ## Sign in with passwordless methods -Your application's users can also sign in using passwordless methods. To learn more, visit the [concepts page for passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/) +Your application's users can also sign in using passwordless methods. To learn more, visit the [concepts page for passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/). ### SMS OTP @@ -1163,7 +1163,7 @@ Amplify.Auth.confirmSignIn( Amplify.Auth.confirmSignIn( "123456", result -> { - // result.nextStep.signInStep should be "DONE" now + // result.getNextStep().getSignInStep() should be "DONE" now }, error -> Log.e("AuthQuickstart", error.toString()) ); @@ -1233,7 +1233,7 @@ RxAmplify.Auth.confirmSignIn(AuthFactorType.SMS_OTP.name()) RxAmplify.Auth.confirmSignIn("123456") .subscribe( result -> { - // result.nextStep.signInStep should be "DONE" now + // result.getNextStep().getSignInStep() should be "DONE" now }, error -> Log.e("AuthQuickstart", error.toString()) ); @@ -1367,7 +1367,7 @@ Amplify.Auth.confirmSignIn( Amplify.Auth.confirmSignIn( "123456", result -> { - // result.nextStep.signInStep should be "DONE" now + // result.getNextStep().getSignInStep() should be "DONE" now }, error -> Log.e("AuthQuickstart", error.toString()) ); @@ -1437,7 +1437,7 @@ RxAmplify.Auth.confirmSignIn(AuthFactorType.EMAIL_OTP.name()) RxAmplify.Auth.confirmSignIn("123456") .subscribe( result -> { - // result.nextStep.signInStep should be "DONE" now + // result.getNextStep().getSignInStep() should be "DONE" now }, error -> Log.e("AuthQuickstart", error.toString()) ); @@ -1589,32 +1589,100 @@ handleNextSignInStep(nextNextStep); + ```java -// Java code +// First confirm the challenge type +Amplify.Auth.confirmSignIn( + AuthFactorType.PASSWORD, // or PASSWORD_SRP + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD) { + // Show UI to collect password + } + }, + error -> Log.e("AuthQuickstart", error.toString()) +); + +// Then pass that password into the confirmSignIn API +Amplify.Auth.confirmSignIn( + "password", + result -> { + // result.getNextStep().getSignInStep() should be "DONE" now + }, + error -> Log.e("AuthQuickstart", error.toString()) +); ``` ```kotlin -// Kotlin code +// First confirm the challenge type +Amplify.Auth.confirmSignIn( + AuthFactorType.PASSWORD.name, // or PASSWORD_SRP + { result -> + if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD) { + // Show UI to collect password + } + }, + { error -> + Log.i("AuthQuickstart", "Failed to sign in", error) + } +) + +// Then pass that password into the confirmSignIn API +Amplify.Auth.confirmSignIn( + "password", + { result -> + // result.nextStep.signInStep should be "DONE" now + }, + { error -> + Log.i("AuthQuickstart", "Failed to sign in", error) + } +) ``` ```kotlin -// Kotlin coroutines code +// First confirm the challenge type +var result = Amplify.Auth.confirmSignIn(AuthFactorType.PASSWORD.name) // or PASSWORD_SRP +if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD) { + // Show UI to collect password +} + +// Then pass that password into the confirmSignIn API +result = Amplify.Auth.confirmSignIn("password") + +// result.nextStep.signInStep should be "DONE" now ``` ```java -// RxJava code +// First confirm the challenge type +RxAmplify.Auth.confirmSignIn(AuthFactorType.PASSWORD.name()) // or PASSWORD_SRP + .subscribe( + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD) { + // Show UI to collect password + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); + +// Then pass that password into the confirmSignIn API +RxAmplify.Auth.confirmSignIn("password") + .subscribe( + result -> { + // result.getNextStep().getSignInStep() should be "DONE" now + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); ``` From 4485e7da0a4c60b30298a4ba63b8d1fdcc373024 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Wed, 27 Nov 2024 13:04:01 -0800 Subject: [PATCH 10/19] Update sign up docs --- .../connect-your-frontend/sign-up/index.mdx | 444 +++++++++++++++++- 1 file changed, 439 insertions(+), 5 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx index 436ce634a0e..6f52c51d93f 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx @@ -528,11 +528,11 @@ export default function App() { - + ## Sign up with passwordless methods -Your application's users can also sign up using passwordless methods. To learn more, visit the [concepts page for passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/) +Your application's users can also sign up using passwordless methods. To learn more, visit the [concepts page for passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/). ### SMS OTP @@ -578,7 +578,168 @@ if (confirmSignUpNextStep.signUpStep === 'DONE') { -{/* */} + + + +```java +// Sign up using a phone number +ArrayList attributes = new ArrayList<>(); +attributes.add(new AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567")); + +Amplify.Auth.signUp( + "username", + null, + AuthSignUpOptions.builder().userAttributes(attributes).build(), + result -> { + if (result.isSignUpComplete()) { + Log.i("AuthQuickstart", "Sign up is complete"); + } else if (result.getNextStep().getSignUpStep() == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) { + Log.i("AuthQuickstart", "Code Deliver Medium: " + + result.getNextStep().getCodeDeliveryDetails().getDeliveryMedium()); + Log.i("AuthQuickstart", "Code Deliver Destination: " + + result.getNextStep().getCodeDeliveryDetails().getDestination()); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) +); + +// Confirm sign up with the OTP received +Amplify.Auth.confirmSignUp( + "username", + "123456", + result -> { + if (result.isSignUpComplete()) { + Log.i("AuthQuickstart", "Sign up is complete"); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) +); +``` + + + + +```kotlin +// Sign up using a phone number +val attributes = listOf( + AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15555551234") +) +val options = + AuthSignUpOptions + .builder() + .userAttributes(attributes) + .build() + +Amplify.Auth.signUp( + "username", + null, + options, + { result -> + if (result.isSignUpComplete) { + Log.i("AuthQuickstart", "Sign up is complete") + } else if (result.nextStep.signUpStep == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) { + Log.i("AuthQuickstart", "Code Deliver Medium: " + + "${result.nextStep.codeDeliveryDetails?.deliveryMedium}") + Log.i("AuthQuickstart", "Code Deliver Destination: " + + "${result.nextStep.codeDeliveryDetails?.destination}") + } + }, + { Log.e("AuthQuickstart", "Failed to sign up", it) } +) + +// Confirm sign up with the OTP received +Amplify.Auth.confirmSignUp( + "username", + "123456", + { result -> + if (result.nextStep.signUpStep == AuthSignUpStep.DONE) { + Log.i("AuthQuickstart", "Sign up is complete") + } + }, + { Log.e("AuthQuickstart", "Failed to sign up", it) } +) +``` + + + + +```kotlin +// Sign up using a phone number +val attributes = listOf( + AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15555551234") +) +val options = + AuthSignUpOptions + .builder() + .userAttributes(attributes) + .build() +var result = Amplify.Auth.signUp("username", null, options) + +if (result.isSignUpComplete) { + Log.i("AuthQuickstart", "Sign up is complete") +} else if (result.nextStep.signUpStep == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) { + Log.i("AuthQuickstart", "Code Deliver Medium: " + + "${result.nextStep.codeDeliveryDetails?.deliveryMedium}") + Log.i("AuthQuickstart", "Code Deliver Destination: " + + "${result.nextStep.codeDeliveryDetails?.destination}") +} + +// Confirm sign up with the OTP received +result = Amplify.Auth.confirmSignUp( + "username", + "123456" +) + +if (result.nextStep.signUpStep == AuthSignUpStep.DONE) { + Log.i("AuthQuickstart", "Sign up is complete") +} +``` + + + + +```java +// Sign up using a phone number +ArrayList attributes = new ArrayList<>(); +attributes.add(new AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567")); + +RxAmplify.Auth.signUp( + "username", + null, + AuthSignUpOptions.builder().userAttributes(attributes).build() +) + .subscribe( + result -> { + if (result.isSignUpComplete()) { + Log.i("AuthQuickstart", "Sign up is complete"); + } else if (result.getNextStep().getSignUpStep() == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) { + Log.i("AuthQuickstart", "Code Deliver Medium: " + + result.getNextStep().getCodeDeliveryDetails().getDeliveryMedium()); + Log.i("AuthQuickstart", "Code Deliver Destination: " + + result.getNextStep().getCodeDeliveryDetails().getDestination()); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); + +// Confirm sign up with the OTP received +RxAmplify.Auth.confirmSignUp( + "username", + "123456" +) + .subscribe( + result -> { + if (result.isSignUpComplete()) { + Log.i("AuthQuickstart", "Sign up is complete"); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); +``` + + + + @@ -726,7 +887,167 @@ if (confirmSignUpNextStep.signUpStep === 'DONE') { -{/* */} + + + +```java +// Sign up using an email address +ArrayList attributes = new ArrayList<>(); +attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com")); + +Amplify.Auth.signUp( + "username", + null, + AuthSignUpOptions.builder().userAttributes(attributes).build(), + result -> { + if (result.isSignUpComplete()) { + Log.i("AuthQuickstart", "Sign up is complete"); + } else if (result.getNextStep().getSignUpStep() == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) { + Log.i("AuthQuickstart", "Code Deliver Medium: " + + result.getNextStep().getCodeDeliveryDetails().getDeliveryMedium()); + Log.i("AuthQuickstart", "Code Deliver Destination: " + + result.getNextStep().getCodeDeliveryDetails().getDestination()); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) +); + +// Confirm sign up with the OTP received +Amplify.Auth.confirmSignUp( + "username", + "123456", + result -> { + if (result.isSignUpComplete()) { + Log.i("AuthQuickstart", "Sign up is complete"); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) +); +``` + + + + +```kotlin +// Sign up using an email address +val attributes = listOf( + AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com") +) +val options = + AuthSignUpOptions + .builder() + .userAttributes(attributes) + .build() + +Amplify.Auth.signUp( + "username", + null, + options, + { result -> + if (result.isSignUpComplete) { + Log.i("AuthQuickstart", "Sign up is complete") + } else if (result.nextStep.signUpStep == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) { + Log.i("AuthQuickstart", "Code Deliver Medium: " + + "${result.nextStep.codeDeliveryDetails?.deliveryMedium}") + Log.i("AuthQuickstart", "Code Deliver Destination: " + + "${result.nextStep.codeDeliveryDetails?.destination}") + } + }, + { Log.e("AuthQuickstart", "Failed to sign up", it) } +) + +// Confirm sign up with the OTP received +Amplify.Auth.confirmSignUp( + "username", + "123456", + { result -> + if (result.nextStep.signUpStep == AuthSignUpStep.DONE) { + Log.i("AuthQuickstart", "Sign up is complete") + } + }, + { Log.e("AuthQuickstart", "Failed to sign up", it) } +) +``` + + + + +```kotlin +// Sign up using an email address +val attributes = listOf( + AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com") +) +val options = + AuthSignUpOptions + .builder() + .userAttributes(attributes) + .build() +var result = Amplify.Auth.signUp("username", null, options) + +if (result.isSignUpComplete) { + Log.i("AuthQuickstart", "Sign up is complete") +} else if (result.nextStep.signUpStep == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) { + Log.i("AuthQuickstart", "Code Deliver Medium: " + + "${result.nextStep.codeDeliveryDetails?.deliveryMedium}") + Log.i("AuthQuickstart", "Code Deliver Destination: " + + "${result.nextStep.codeDeliveryDetails?.destination}") +} + +// Confirm sign up with the OTP received +result = Amplify.Auth.confirmSignUp( + "username", + "123456" +) + +if (result.nextStep.signUpStep == AuthSignUpStep.DONE) { + Log.i("AuthQuickstart", "Sign up is complete") +} +``` + + + + +```java +// Sign up using an email address +ArrayList attributes = new ArrayList<>(); +attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com")); + +RxAmplify.Auth.signUp( + "username", + null, + AuthSignUpOptions.builder().userAttributes(attributes).build() +) + .subscribe( + result -> { + if (result.isSignUpComplete()) { + Log.i("AuthQuickstart", "Sign up is complete"); + } else if (result.getNextStep().getSignUpStep() == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) { + Log.i("AuthQuickstart", "Code Deliver Medium: " + + result.getNextStep().getCodeDeliveryDetails().getDeliveryMedium()); + Log.i("AuthQuickstart", "Code Deliver Destination: " + + result.getNextStep().getCodeDeliveryDetails().getDestination()); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); + +// Confirm sign up with the OTP received +RxAmplify.Auth.confirmSignUp( + "username", + "123456" +) + .subscribe( + result -> { + if (result.isSignUpComplete()) { + Log.i("AuthQuickstart", "Sign up is complete"); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); +``` + + + @@ -854,7 +1175,120 @@ if (confirmSignUpNextStep.signUpStep === 'COMPLETE_AUTO_SIGN_IN') { -{/* */} + + + +```java +private void confirmSignUp(String username, String confirmationCode) { + // Confirm sign up with the OTP received then auto sign in + Amplify.Auth.confirmSignUp( + username, + confirmationCode, + result -> { + if (result.getNextStep().getSignUpStep() == AuthSignUpStep.COMPLETE_AUTO_SIGN_IN) { + Log.i("AuthQuickstart", "Sign up is complete, auto sign in"); + autoSignIn(); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); +} + +private void autoSignIn() { + Amplify.Auth.autoSignIn( + result -> Log.i("AuthQuickstart", "Sign in is complete"), + error -> Log.e("AuthQuickstart", error.toString()) + ); +} +``` + + + + +```kotlin +fun confirmSignUp(username: String, confirmationCode: String) { + // Confirm sign up with the OTP received + Amplify.Auth.confirmSignUp( + username, + confirmationCode, + { signUpResult -> + if (signUpResult.nextStep.signUpStep == AuthSignUpStep.COMPLETE_AUTO_SIGN_IN) { + Log.i("AuthQuickstart", "Sign up is complete, auto sign in") + autoSignIn() + } + }, + { Log.e("AuthQuickstart", "Failed to sign up", it) } + ) +} +fun autoSignIn() { + Amplify.Auth.autoSignIn( + { signInResult -> + Log.i("AuthQuickstart", "Sign in is complete") + }, + { Log.e("AuthQuickstart", "Failed to sign in", it) } + ) +} +``` + + + + +```kotlin +suspend fun confirmSignUp(username: String, confirmationCode: String) { + // Confirm sign up with the OTP received then auto sign in + val result = Amplify.Auth.confirmSignUp( + "username", + "123456" + ) + + if (result.nextStep.signUpStep == AuthSignUpStep.COMPLETE_AUTO_SIGN_IN) { + Log.i("AuthQuickstart", "Sign up is complete, auto sign in") + autoSignIn() + } +} + +suspend fun autoSignIn() { + val result = Amplify.Auth.autoSignIn() + if (result.isSignedIn) { + Log.i("AuthQuickstart", "Sign in is complete") + } else { + Log.e("AuthQuickstart", "Sign in did not complete $result") + } +} +``` + + + + +```java +private void confirmSignUp(String username, String confirmationCode) { + // Confirm sign up with the OTP received then auto sign in + RxAmplify.Auth.confirmSignUp( + username, + confirmationCode + ) + .subscribe( + result -> { + if (result.getNextStep().getSignUpStep() == AuthSignUpStep.COMPLETE_AUTO_SIGN_IN) { + Log.i("AuthQuickstart", "Sign up is complete, auto sign in"); + autoSignIn(); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); +} + +private void autoSignIn() { + RxAmplify.Auth.autoSignIn() + .subscribe( + result -> Log.i("AuthQuickstart", "Sign in is complete" + result.toString()), + error -> Log.e("AuthQuickstart", error.toString()) + ); +} +``` + + + From bd221aaefcc67d4d7cccd349934d7bf44df6da92 Mon Sep 17 00:00:00 2001 From: Matt Creaser Date: Wed, 27 Nov 2024 17:10:02 -0400 Subject: [PATCH 11/19] Add Android's WebAuthn details to `connect-your-frontend/sign-in/index.mdx` --- .../connect-your-frontend/sign-in/index.mdx | 147 +++++++++++++++--- 1 file changed, 124 insertions(+), 23 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index 9695a7a8114..be88b769a50 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -803,10 +803,10 @@ func confirmSignIn() -> AnyCancellable { ## Sign in with an external identity provider -To sign in using an external identity provider such as Google, use the `signInWithRedirect` function. - +To sign in using an external identity provider such as Google, use the `signInWithRedirect` function. + ```ts import { signInWithRedirect } from "aws-amplify/auth" @@ -844,7 +844,10 @@ await autoSignIn(); ``` - + + +To sign in using an external identity provider such as Google, use the `signInWithRedirect` function. ### Install native module @@ -883,6 +886,8 @@ Add the `intent-filter` to your application's main activity, replacing `myapp` w +To sign in using an external identity provider such as Google, use the `signInWithWebUI` function. + ### How It Works Sign-in with web UI will display the sign-in UI inside a webview. After the sign-in process is complete, the sign-in UI will redirect back to your app. @@ -949,7 +954,10 @@ Future socialSignIn() async { ``` -## Update AndroidManifest.xml + +To sign in using an external identity provider such as Google, use the `signInWithSocialWebUI` function. + +### Update AndroidManifest.xml Add the following activity and queries tag to your app's `AndroidManifest.xml` file, replacing `myapp` with your redirect URI prefix if necessary: @@ -971,7 +979,7 @@ your redirect URI prefix if necessary: ``` -## Launch Social Web UI Sign In +### Launch Social Web UI Sign In Sweet! You're now ready to launch sign in with your social provider's web UI. @@ -1034,7 +1042,10 @@ RxAmplify.Auth.signInWithSocialWebUI(AuthProvider.facebook(), this) -## Update Info.plist + +To sign in using an external identity provider such as Google, use the `signInWithWebUI` function. + +### Update Info.plist Sign-in with web UI requires the Amplify plugin to show up the sign-in UI inside a webview. After the sign-in process is complete it will redirect back to your app. You have to enable this in your app's `Info.plist`. Right click Info.plist and then choose Open As > Source Code. Add the following entry in the URL scheme: @@ -1064,7 +1075,7 @@ You have to enable this in your app's `Info.plist`. Right click Info.plist and t When creating a new SwiftUI app using Xcode 13 no longer require configuration files such as the Info.plist. If you are missing this file, click on the project target, under Info, Url Types, and click '+' to add a new URL Type. Add `myapp` to the URL Schemes. You should see the Info.plist file now with the entry for CFBundleURLSchemes. -## Launch Social Web UI Sign In +### Launch Social Web UI Sign In Invoke the following API with the provider you're using (shown with Facebook below): @@ -1140,7 +1151,7 @@ handleNextSignInStep(nextStep); -To request an OTP code via SMS for authentication, you must pass the SMS auth factor type (`AuthFactorType.SMS_OTP`) to the `confirmSignIn` API. +To request an OTP code via SMS for authentication, you pass the `challengeResponse` for `AuthFactorType.SMS_OTP` to the `confirmSignIn` API. Amplify will respond appropriately to Cognito and return the challenge as the sign in next step: `CONFIRM_SIGN_IN_WITH_OTP_CODE`. You will call `confirmSignIn` again, this time with the OTP that your user provides. @@ -1150,7 +1161,7 @@ Amplify will respond appropriately to Cognito and return the challenge as the si ```java // First confirm the challenge type Amplify.Auth.confirmSignIn( - AuthFactorType.SMS_OTP.name(), + AuthFactorType.SMS_OTP.getChallengeResponse(), result -> { if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { // Show UI to collect OTP @@ -1175,7 +1186,7 @@ Amplify.Auth.confirmSignIn( ```kotlin // First confirm the challenge type Amplify.Auth.confirmSignIn( - AuthFactorType.SMS_OTP.name, + AuthFactorType.SMS_OTP.challengeResponse, { result -> if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { // Show UI to collect OTP @@ -1203,7 +1214,7 @@ Amplify.Auth.confirmSignIn( ```kotlin // First confirm the challenge type -var result = Amplify.Auth.confirmSignIn(AuthFactorType.SMS_OTP.name) +var result = Amplify.Auth.confirmSignIn(AuthFactorType.SMS_OTP.challengeResponse) if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { // Show UI to collect OTP } @@ -1219,7 +1230,7 @@ result = Amplify.Auth.confirmSignIn("123456") ```java // First confirm the challenge type -RxAmplify.Auth.confirmSignIn(AuthFactorType.SMS_OTP.name()) +RxAmplify.Auth.confirmSignIn(AuthFactorType.SMS_OTP.getChallengeResponse()) .subscribe( result -> { if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { @@ -1344,7 +1355,7 @@ handleNextSignInStep(nextStep); -To request an OTP code via email for authentication, you must pass the email auth factor type (`AuthFactorType.EMAIL_OTP`) to the `confirmSignIn` API. +To request an OTP code via email for authentication, you pass the `challengeResponse` for `AuthFactorType.EMAIL_OTP` to the `confirmSignIn` API. Amplify will respond appropriately to Cognito and return the challenge as the sign in next step: `CONFIRM_SIGN_IN_WITH_OTP_CODE`. You will call `confirmSignIn` again, this time with the OTP that your user provides. @@ -1354,7 +1365,7 @@ Amplify will respond appropriately to Cognito and return the challenge as the si ```java // First confirm the challenge type Amplify.Auth.confirmSignIn( - AuthFactorType.EMAIL_OTP.name(), + AuthFactorType.EMAIL_OTP.getChallengeResponse(), result -> { if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { // Show UI to collect OTP @@ -1379,7 +1390,7 @@ Amplify.Auth.confirmSignIn( ```kotlin // First confirm the challenge type Amplify.Auth.confirmSignIn( - AuthFactorType.EMAIL_OTP.name, + AuthFactorType.EMAIL_OTP.challengeResponse, { result -> if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { // Show UI to collect OTP @@ -1407,7 +1418,7 @@ Amplify.Auth.confirmSignIn( ```kotlin // First confirm the challenge type -var result = Amplify.Auth.confirmSignIn(AuthFactorType.EMAIL_OTP.name) +var result = Amplify.Auth.confirmSignIn(AuthFactorType.EMAIL_OTP.challengeResponse) if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { // Show UI to collect OTP } @@ -1423,7 +1434,7 @@ result = Amplify.Auth.confirmSignIn("123456") ```java // First confirm the challenge type -RxAmplify.Auth.confirmSignIn(AuthFactorType.EMAIL_OTP.name()) +RxAmplify.Auth.confirmSignIn(AuthFactorType.EMAIL_OTP.getChallengeResponse()) .subscribe( result -> { if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) { @@ -1547,7 +1558,97 @@ handleNextSignInStep(nextStep); -{/* */} +To sign in with WebAuthn, you pass the `challengeResponse` for `AuthFactorType.WEB_AUTHN` to the `confirmSignIn` API. Amplify will invoke Android's Credential Manager to retrieve a PassKey, and the user will be shown a system UI to authorize the PassKey access. This flow +completes without any additional interaction from your application, so there is only one `confirmSignIn` call needed for WebAuthn. + + +Amplify requires an `Activity` reference to attach the PassKey UI to your Application's [Task](https://developer.android.com/guide/components/activities/tasks-and-back-stack) when using WebAuthn - if an `Activity` is not supplied then the UI will appear in a separate Task. For this reason, we strongly recommend passing the `callingActivity` option to both the `signIn` and `confirmSignIn` APIs if your application uses the `USER_AUTH` flow. + + + + + +```java +// Pass the calling activity +AuthSignInOptions options = AWSCognitoAuthConfirmSignInOptions.builder() + .callingActivity(activity) + .build(); + +// Confirm WebAuthn as the challenge type +Amplify.Auth.confirmSignIn( + AuthFactorType.WEB_AUTHN.getChallengeResponse(), + options, + result -> Log.i("AuthQuickStart", "Next sign in step: " + result.getNextStep()), + error -> Log.e("AuthQuickstart", "Failed to sign in", error) +); +``` + + + + +```kotlin +// Pass the calling activity +val options = AWSCognitoAuthConfirmSignInOptions.builder() + .callingActivity(activity) + .build() + +// Confirm WebAuthn as the challenge type +Amplify.Auth.confirmSignIn( + AuthFactorType.WEB_AUTHN.name, + options, + { result -> Log.i("AuthQuickStart", "Next sign in step: ${result.nextStep}") }, + { error -> Log.i("AuthQuickstart", "Failed to sign in", error) } +) +``` + + + + +```kotlin +// Pass the calling activity +val options = AWSCognitoAuthConfirmSignInOptions.builder() + .callingActivity(activity) + .build() + +try { + // Confirm WebAuthn as the challenge type + var result = Amplify.Auth.confirmSignIn( + challengeResponse = AuthFactorType.WEB_AUTHN.challengeResponse, + options = options + ) + Log.i("AuthQuickStart", "Next sign in step: ${result.nextStep}") +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Failed to sign in", error) +} +``` + + + + +```java +// Pass the calling activity +AuthSignInOptions options = AWSCognitoAuthConfirmSignInOptions.builder() + .callingActivity(activity) + .build(); + +// Confirm WebAuthn as the challenge type +RxAmplify.Auth.confirmSignIn(AuthFactorType.WEB_AUTHN.getChallengeResponse(), options) + .subscribe( + result -> Log.i("AuthQuickStart", "Next sign in step: " + result.getNextStep()), + error -> Log.e("AuthQuickstart", "Failed to sign in", error) + ); +``` + + + + +Using WebAuthn sign in may result in a number of possible exception types. + +- `UserCancelledException` - If the user declines to authorize access to the PassKey in the system UI. You can retry the WebAuthn flow by invoking `confirmSignIn` again, or restart the `signIn` process to select a different `AuthFactorType`. +- `WebAuthnNotEnabledException` - This indicates WebAuthn is not enabled in your user pool. +- `WebAuthnNotSupportedException` - This indicates WebAuthn is not supported on the user's device. +- `WebAuthnRpMismatchException` - This indicates there is a problem with the `assetlinks.json` file deployed to your relying party. +- `WebAuthnFailedException` - This exception is used for other errors that may occur with WebAuthn. Inspect the `cause` to determine the best course of action. @@ -1565,7 +1666,7 @@ handleNextSignInStep(nextStep); ### Password or SRP -Traditional password based authentication is available from this flow as well. To initiate this flow from select challenge, either `PASSWORD` or `PASSWORD_SRP` is passed as the challenge response. +Traditional password based authentication is available from the `USER_AUTH` flow as well. To initiate this flow from select challenge, either `PASSWORD` or `PASSWORD_SRP` is passed as the challenge response. @@ -1596,7 +1697,7 @@ handleNextSignInStep(nextNextStep); ```java // First confirm the challenge type Amplify.Auth.confirmSignIn( - AuthFactorType.PASSWORD, // or PASSWORD_SRP + AuthFactorType.PASSWORD.getChallengeResponse(), // or PASSWORD_SRP result -> { if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD) { // Show UI to collect password @@ -1621,7 +1722,7 @@ Amplify.Auth.confirmSignIn( ```kotlin // First confirm the challenge type Amplify.Auth.confirmSignIn( - AuthFactorType.PASSWORD.name, // or PASSWORD_SRP + AuthFactorType.PASSWORD.challengeResponse, // or PASSWORD_SRP { result -> if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD) { // Show UI to collect password @@ -1649,7 +1750,7 @@ Amplify.Auth.confirmSignIn( ```kotlin // First confirm the challenge type -var result = Amplify.Auth.confirmSignIn(AuthFactorType.PASSWORD.name) // or PASSWORD_SRP +var result = Amplify.Auth.confirmSignIn(AuthFactorType.PASSWORD.challengeResponse) // or PASSWORD_SRP if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD) { // Show UI to collect password } @@ -1665,7 +1766,7 @@ result = Amplify.Auth.confirmSignIn("password") ```java // First confirm the challenge type -RxAmplify.Auth.confirmSignIn(AuthFactorType.PASSWORD.name()) // or PASSWORD_SRP +RxAmplify.Auth.confirmSignIn(AuthFactorType.PASSWORD.getChallengeResponse()) // or PASSWORD_SRP .subscribe( result -> { if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD) { From 7c8344beb56500639ba185b4b4373ebb5b952ae3 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Wed, 27 Nov 2024 14:57:27 -0800 Subject: [PATCH 12/19] Fix some small issues and update multi-step sign in --- cspell.json | 3 +- .../multi-step-sign-in/index.mdx | 448 ++++++++++-------- .../connect-your-frontend/sign-in/index.mdx | 16 +- .../switching-authentication-flows/index.mdx | 48 +- 4 files changed, 273 insertions(+), 242 deletions(-) diff --git a/cspell.json b/cspell.json index 8aa9138f087..c2c0df0f66b 100644 --- a/cspell.json +++ b/cspell.json @@ -1616,7 +1616,8 @@ "jamba", "webauthn", "knowledgebases", - "rehype" + "rehype", + "assetlinks" ], "flagWords": ["hte", "full-stack", "Full-stack", "Full-Stack", "sudo"], "patterns": [ diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx index 9aae5c63efe..8420a40d3e0 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx @@ -1067,11 +1067,9 @@ The `nextStep` property is of enum type `AuthSignInStep`. Depending on its value ```java try { - AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder().authFlowType(AuthFlowType.USER_SRP_AUTH).build(); Amplify.Auth.signIn( "username", "password", - options, result -> { AuthNextSignInStep nextStep = result.getNextStep(); @@ -1110,10 +1108,10 @@ try { break; } case CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION: { - Log.i("AuthQuickstart", "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors()); - // Prompt the user to select which authentication factor they want to use to sign-in - // Then invoke `confirmSignIn` api with that selection - break; + Log.i("AuthQuickstart", "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors()); + // Prompt the user to select which authentication factor they want to use to sign-in + // Then invoke `confirmSignIn` api with that selection + break; } case CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE: { Log.i("AuthQuickstart", "SMS code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); @@ -1184,91 +1182,103 @@ try { ```kotlin -val options = AWSCognitoAuthSignInOptions.builder().authFlowType(AuthFlowType.USER_SRP_AUTH).build() try { - Amplify.Auth.signIn( - "username", - "password", - options, - { result -> - val nextStep = result.nextStep - when(nextStep.signInStep){ - AuthSignInStep.CONFIRM_SIGN_IN_WITH_TOTP_CODE -> { - Log.i("AuthQuickstart", "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 - } - AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION -> { - Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); - Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); - // Prompt the user to select the MFA type they want to setup - // Then invoke `confirmSignIn` api with the MFA type - } - AuthSignInStep.CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP -> { - Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); - // Prompt the user to enter the email address they would like to use to receive OTPs - // Then invoke `confirmSignIn` api with the email address - } - AuthSignInStep.CONTINUE_SIGN_IN_WITH_TOTP_SETUP -> { - Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP") - Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app ${nextStep.totpSetupDetails.sharedSecret}") - // Prompt the user to enter the TOTP code generated in their authenticator app - // Then invoke `confirmSignIn` api with the code - } - AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SELECTION -> { - Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type") - Log.i("AuthQuickstart", "Allowed MFA types ${nextStep.allowedMFATypes}") - // Prompt the user to select the MFA type they want to use - // Then invoke `confirmSignIn` api with the MFA type - } - AuthSignInStep.CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE -> { - Log.i("AuthQuickstart", "SMS code sent to ${nextStep.codeDeliveryDetails?.destination}") - Log.i("AuthQuickstart", "Additional Info ${nextStep.additionalInfo}") - // Prompt the user to enter the SMS MFA code they received - // Then invoke `confirmSignIn` api with the code - } - AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP -> { - Log.i("AuthQuickstart", "OTP code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); - Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); - // Prompt the user to enter the OTP MFA code they received - // Then invoke `confirmSignIn` api with the code - } - AuthSignInStep.CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE -> { - Log.i("AuthQuickstart","Custom challenge, additional info: ${nextStep.additionalInfo}") - // Prompt the user to enter custom challenge answer - // Then invoke `confirmSignIn` api with the answer - } - AuthSignInStep.CONFIRM_SIGN_IN_WITH_NEW_PASSWORD -> { - Log.i("AuthQuickstart", "Sign in with new password, additional info: ${nextStep.additionalInfo}") - // Prompt the user to enter a new password - // Then invoke `confirmSignIn` api with new password - } - AuthSignInStep.DONE -> { - Log.i("AuthQuickstart", "SignIn complete") - // User has successfully signed in to the app - } - } + Amplify.Auth.signIn( + "username", + "password", + { result -> + val nextStep = result.nextStep + when(nextStep.signInStep){ + AuthSignInStep.CONFIRM_SIGN_IN_WITH_TOTP_CODE -> { + Log.i("AuthQuickstart", "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 + } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION -> { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup") + Log.i("AuthQuickstart", "Allowed MFA types for setup ${nextStep.allowedMFATypes}") + // Prompt the user to select the MFA type they want to setup + // Then invoke `confirmSignIn` api with the MFA type + } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP -> { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA") + // Prompt the user to enter the email address they would like to use to receive OTPs + // Then invoke `confirmSignIn` api with the email address + } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_TOTP_SETUP -> { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP") + Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app ${nextStep.totpSetupDetails?.sharedSecret}") + // Prompt the user to enter the TOTP code generated in their authenticator app + // Then invoke `confirmSignIn` api with the code + } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SELECTION -> { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type") + Log.i("AuthQuickstart", "Allowed MFA types ${nextStep.allowedMFATypes}") + // Prompt the user to select the MFA type they want to use + // Then invoke `confirmSignIn` api with the MFA type + } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION -> { + Log.i("AuthQuickstart", "Available authentication factors for this user: ${result.nextStep.availableFactors}") + // Prompt the user to select which authentication factor they want to use to sign-in + // Then invoke `confirmSignIn` api with that selection + } + AuthSignInStep.CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE -> { + Log.i("AuthQuickstart", "SMS code sent to ${nextStep.codeDeliveryDetails?.destination}") + Log.i("AuthQuickstart", "Additional Info ${nextStep.additionalInfo}") + // Prompt the user to enter the SMS MFA code they received + // Then invoke `confirmSignIn` api with the code + } + AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP -> { + Log.i("AuthQuickstart", "OTP code sent to ${nextStep.codeDeliveryDetails?.destination}") + Log.i("AuthQuickstart", "Additional Info ${nextStep.additionalInfo}") + // Prompt the user to enter the OTP MFA code they received + // Then invoke `confirmSignIn` api with the code + } + AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD -> { + Log.i("AuthQuickstart", "Received next step as confirm sign in with password") + // Prompt the user to enter their password + // Then invoke `confirmSignIn` api with that password + } + AuthSignInStep.CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE -> { + Log.i("AuthQuickstart","Custom challenge, additional info: ${nextStep.additionalInfo}") + // Prompt the user to enter custom challenge answer + // Then invoke `confirmSignIn` api with the answer + } + AuthSignInStep.CONFIRM_SIGN_IN_WITH_NEW_PASSWORD -> { + Log.i("AuthQuickstart", "Sign in with new password, additional info: ${nextStep.additionalInfo}") + // Prompt the user to enter a new password + // Then invoke `confirmSignIn` api with new password + } + AuthSignInStep.DONE -> { + Log.i("AuthQuickstart", "SignIn complete") + // User has successfully signed in to the app + } + } - } - ) { error -> - if (error is UserNotConfirmedException) { - // 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. - Log.i("AuthQuickstart", "Signup confirmation required", error) - } else if (error is PasswordResetRequiredException) { - // 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. - Log.i("AuthQuickstart", "Password reset required", error) - } else { - Log.e("AuthQuickstart", "Unexpected error occurred: $error") - } - } + } + ) { error -> + when (error) { + is UserNotConfirmedException -> { + // 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. + Log.e("AuthQuickstart", "Signup confirmation required", error) + } + is PasswordResetRequiredException -> { + // 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. + Log.e("AuthQuickstart", "Password reset required", error) + } + else -> { + Log.e("AuthQuickstart", "Unexpected error occurred: $error") + } + } + } } catch (error: Exception) { Log.e("AuthQuickstart", "Unexpected error occurred: $error") } @@ -1279,13 +1289,10 @@ try { ```kotlin -val options = - AWSCognitoAuthSignInOptions.builder().authFlowType(AuthFlowType.USER_SRP_AUTH).build() try { val result = Amplify.Auth.signIn( "username", - "password", - options + "password" ) val nextStep = result.nextStep when (nextStep.signInStep) { @@ -1295,19 +1302,19 @@ try { // Then invoke `confirmSignIn` api with the code } AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION -> { - Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); - Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup") + Log.i("AuthQuickstart", "Allowed MFA types for setup ${nextStep.allowedMFATypes}") // Prompt the user to select the MFA type they want to setup // Then invoke `confirmSignIn` api with the MFA type } AuthSignInStep.CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP -> { - Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA") // Prompt the user to enter the email address they would like to use to receive OTPs // Then invoke `confirmSignIn` api with the email address } AuthSignInStep.CONTINUE_SIGN_IN_WITH_TOTP_SETUP -> { Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP") - Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app ${nextStep.totpSetupDetails.sharedSecret}") + Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app ${nextStep.totpSetupDetails?.sharedSecret}") // Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code } @@ -1317,6 +1324,11 @@ try { // Prompt the user to select the MFA type they want to use // Then invoke `confirmSignIn` api with the MFA type } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION -> { + Log.i("AuthQuickstart", "Available authentication factors for this user: ${result.nextStep.availableFactors}") + // Prompt the user to select which authentication factor they want to use to sign-in + // Then invoke `confirmSignIn` api with that selection + } AuthSignInStep.CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE -> { Log.i("AuthQuickstart", "SMS code sent to ${nextStep.codeDeliveryDetails?.destination}") Log.i("AuthQuickstart", "Additional Info ${nextStep.additionalInfo}") @@ -1329,16 +1341,18 @@ try { // Prompt the user to enter the OTP MFA code they received // Then invoke `confirmSignIn` api with the code } + AuthSignInStep.CONFIRM_SIGN_IN_WITH_PASSWORD -> { + Log.i("AuthQuickstart", "Received next step as confirm sign in with password") + // Prompt the user to enter their password + // Then invoke `confirmSignIn` api with that password + } AuthSignInStep.CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE -> { - Log.i("AuthQuickstart", "Custom challenge, additional info: ${nextStep.additionalInfo}") + Log.i("AuthQuickstart","Custom challenge, additional info: ${nextStep.additionalInfo}") // Prompt the user to enter custom challenge answer // Then invoke `confirmSignIn` api with the answer } AuthSignInStep.CONFIRM_SIGN_IN_WITH_NEW_PASSWORD -> { - Log.i( - "AuthQuickstart", - "Sign in with new password, additional info: ${nextStep.additionalInfo}" - ) + Log.i("AuthQuickstart", "Sign in with new password, additional info: ${nextStep.additionalInfo}") // Prompt the user to enter a new password // Then invoke `confirmSignIn` api with new password } @@ -1348,23 +1362,27 @@ try { } } } catch (error: Exception) { - if (error is UserNotConfirmedException) { - // 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. - Log.i("AuthQuickstart", "Signup confirmation required", error) - } else if (error is PasswordResetRequiredException) { - // 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. - Log.i("AuthQuickstart", "Password reset required", error) - } else { - Log.e("AuthQuickstart", "Unexpected error occurred: $error") - } + when (error) { + is UserNotConfirmedException -> { + // 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. + Log.e("AuthQuickstart", "Signup confirmation required", error) + } + is PasswordResetRequiredException -> { + // 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. + Log.e("AuthQuickstart", "Password reset required", error) + } + else -> { + Log.e("AuthQuickstart", "Unexpected error occurred: $error") + } + } } ``` @@ -1373,98 +1391,108 @@ try { ```java - -AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder().authFlowType(AuthFlowType.USER_SRP_AUTH).build(); -RxAmplify.Auth.signIn("username", "password", options).subscribe( - result -> - { - AuthNextSignInStep nextStep = result.getNextStep(); - switch (nextStep.getSignInStep()) { - case CONFIRM_SIGN_IN_WITH_TOTP_CODE: { - Log.i("AuthQuickstart", "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 - break; - } - case CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION: { - Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); - Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); - // Prompt the user to select the MFA type they want to setup - // Then invoke `confirmSignIn` api with the MFA type - break; - } - case CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP: { - Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); - // Prompt the user to enter the email address they would like to use to receive OTPs - // Then invoke `confirmSignIn` api with the email address - break; - } - case CONTINUE_SIGN_IN_WITH_TOTP_SETUP: { - Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP"); - Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app" + nextStep.getTotpSetupDetails().getSharedSecret()); - // Prompt the user to enter the TOTP code generated in their authenticator app - // Then invoke `confirmSignIn` api with the code - break; - } - case CONTINUE_SIGN_IN_WITH_MFA_SELECTION: { - Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type"); - Log.i("AuthQuickstart", "Allowed MFA type" + nextStep.getAllowedMFATypes()); - // Prompt the user to select the MFA type they want to use - // Then invoke `confirmSignIn` api with the MFA type - break; - } - case CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE: { - Log.i("AuthQuickstart", "SMS code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); - Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); - // Prompt the user to enter the SMS MFA code they received - // Then invoke `confirmSignIn` api with the code - break; - } - case CONFIRM_SIGN_IN_WITH_OTP: { - Log.i("AuthQuickstart", "OTP code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); - Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); - // Prompt the user to enter the OTP MFA code they received - // Then invoke `confirmSignIn` api with the code - break; - } - case CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE: { - Log.i("AuthQuickstart", "Custom challenge, additional info: " + nextStep.getAdditionalInfo()); - // Prompt the user to enter custom challenge answer - // Then invoke `confirmSignIn` api with the answer - break; - } - case CONFIRM_SIGN_IN_WITH_NEW_PASSWORD: { - Log.i("AuthQuickstart", "Sign in with new password, additional info: " + nextStep.getAdditionalInfo()); - // Prompt the user to enter a new password - // Then invoke `confirmSignIn` api with new password - break; - } - case DONE: { - Log.i("AuthQuickstart", "SignIn complete"); - // User has successfully signed in to the app - break; - } +RxAmplify.Auth.signIn("username", "password").subscribe( + result -> + { + AuthNextSignInStep nextStep = result.getNextStep(); + switch (nextStep.getSignInStep()) { + case CONFIRM_SIGN_IN_WITH_TOTP_CODE: { + Log.i("AuthQuickstart", "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 + break; + } + case CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION: { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); + Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); + // Prompt the user to select the MFA type they want to setup + // Then invoke `confirmSignIn` api with the MFA type + break; + } + case CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP: { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); + // Prompt the user to enter the email address they would like to use to receive OTPs + // Then invoke `confirmSignIn` api with the email address + break; + } + case CONTINUE_SIGN_IN_WITH_TOTP_SETUP: { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP"); + Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app" + nextStep.getTotpSetupDetails().getSharedSecret()); + // Prompt the user to enter the TOTP code generated in their authenticator app + // Then invoke `confirmSignIn` api with the code + break; + } + case CONTINUE_SIGN_IN_WITH_MFA_SELECTION: { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type"); + Log.i("AuthQuickstart", "Allowed MFA type" + nextStep.getAllowedMFATypes()); + // Prompt the user to select the MFA type they want to use + // Then invoke `confirmSignIn` api with the MFA type + break; + } + case CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION: { + Log.i("AuthQuickstart", "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors()); + // Prompt the user to select which authentication factor they want to use to sign-in + // Then invoke `confirmSignIn` api with that selection + break; + } + case CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE: { + Log.i("AuthQuickstart", "SMS code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); + Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); + // Prompt the user to enter the SMS MFA code they received + // Then invoke `confirmSignIn` api with the code + break; + } + case CONFIRM_SIGN_IN_WITH_OTP: { + Log.i("AuthQuickstart", "OTP code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); + Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); + // Prompt the user to enter the OTP MFA code they received + // Then invoke `confirmSignIn` api with the code + break; + } + case CONFIRM_SIGN_IN_WITH_PASSWORD: { + Log.i("AuthQuickstart", "Received next step as confirm sign in with password"); + // Prompt the user to enter their password + // Then invoke `confirmSignIn` api with that password + break; + } + case CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE: { + Log.i("AuthQuickstart", "Custom challenge, additional info: " + nextStep.getAdditionalInfo()); + // Prompt the user to enter custom challenge answer + // Then invoke `confirmSignIn` api with the answer + break; + } + case CONFIRM_SIGN_IN_WITH_NEW_PASSWORD: { + Log.i("AuthQuickstart", "Sign in with new password, additional info: " + nextStep.getAdditionalInfo()); + // Prompt the user to enter a new password + // Then invoke `confirmSignIn` api with new password + break; + } + case DONE: { + Log.i("AuthQuickstart", "SignIn complete"); + // User has successfully signed in to the app + break; } - }, - error -> { - if (error instanceof UserNotConfirmedException) { - // 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. - Log.i("AuthQuickstart", "Signup confirmation required" + error); - } else if (error instanceof PasswordResetRequiredException) { - // 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. - Log.i("AuthQuickstart", "Password reset required" + error); - } else { - Log.e("AuthQuickstart", "SignIn failed: " + error); - } } + }, + error -> { + if (error instanceof UserNotConfirmedException) { + // 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. + Log.i("AuthQuickstart", "Signup confirmation required" + error); + } else if (error instanceof PasswordResetRequiredException) { + // 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. + Log.i("AuthQuickstart", "Password reset required" + error); + } else { + Log.e("AuthQuickstart", "SignIn failed: " + error); + } + } ); ``` @@ -1625,6 +1653,8 @@ If the next step is `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION`, the user must s If the next step is `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`, the user must select an authentication factor to use either because they did not specify one or because the one they chose is not supported (e.g. selecting SMS when they don't have a phone number registered to their account). Amplify Auth currently supports SMS, email, password, and webauthn as authentication factors. After the user selects an authentication method, your implementation must pass the selected authentication method to Amplify Auth using `confirmSignIn` API. +Visit the [sign-in documentation](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/#sign-in-with-passwordless-methods) to see examples on how to call the `confirmSignIn` API. + ## Confirm sign-in with custom challenge If the next step is `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE`, Amplify Auth is awaiting completion of a custom authentication challenge. The challenge is based on the Lambda trigger you setup when you configured a [custom sign in flow](/[platform]/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/#sign-in-a-user). To complete this step, you should prompt the user for the custom challenge answer, and pass the answer to the `confirmSignIn` API. diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index be88b769a50..420b3d1d606 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -281,8 +281,8 @@ The `signIn` API response will include a `nextStep` property, which can be used | `CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | | `CONFIRM_SIGN_IN_WITH_OTP` | The sign-in must be confirmed with a code from the user (sent via SMS or Email). Complete the process with `confirmSignIn`. | | `CONFIRM_SIGN_IN_WITH_PASSWORD` | The sign-in must be confirmed with the password from the user. Complete the process with `confirmSignIn`. | -| `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION` | The user must select their mode of MFA verification to setup. Complete the process by passing either `MFAType.EMAIL.challengeResponse` or `MFAType.TOTP.challengeResponse` to `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | | `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` | The user must select their mode of first factor authentication. Complete the process by passing the desired mode to the `challengeResponse` field of `confirmSignIn`. | @@ -1193,7 +1193,7 @@ Amplify.Auth.confirmSignIn( } }, { error -> - Log.i("AuthQuickstart", "Failed to sign in", error) + Log.e("AuthQuickstart", "Failed to sign in", error) } ) @@ -1204,7 +1204,7 @@ Amplify.Auth.confirmSignIn( // result.nextStep.signInStep should be "DONE" now }, { error -> - Log.i("AuthQuickstart", "Failed to sign in", error) + Log.e("AuthQuickstart", "Failed to sign in", error) } ) ``` @@ -1397,7 +1397,7 @@ Amplify.Auth.confirmSignIn( } }, { error -> - Log.i("AuthQuickstart", "Failed to sign in", error) + Log.e("AuthQuickstart", "Failed to sign in", error) } ) @@ -1408,7 +1408,7 @@ Amplify.Auth.confirmSignIn( // result.nextStep.signInStep should be "DONE" now }, { error -> - Log.i("AuthQuickstart", "Failed to sign in", error) + Log.e("AuthQuickstart", "Failed to sign in", error) } ) ``` @@ -1597,7 +1597,7 @@ Amplify.Auth.confirmSignIn( AuthFactorType.WEB_AUTHN.name, options, { result -> Log.i("AuthQuickStart", "Next sign in step: ${result.nextStep}") }, - { error -> Log.i("AuthQuickstart", "Failed to sign in", error) } + { error -> Log.e("AuthQuickstart", "Failed to sign in", error) } ) ``` @@ -1729,7 +1729,7 @@ Amplify.Auth.confirmSignIn( } }, { error -> - Log.i("AuthQuickstart", "Failed to sign in", error) + Log.e("AuthQuickstart", "Failed to sign in", error) } ) @@ -1740,7 +1740,7 @@ Amplify.Auth.confirmSignIn( // result.nextStep.signInStep should be "DONE" now }, { error -> - Log.i("AuthQuickstart", "Failed to sign in", error) + Log.e("AuthQuickstart", "Failed to sign in", error) } ) ``` diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index 6fd4b05283e..92af8979bcb 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -319,10 +319,10 @@ If the desired first factor is known before the sign in flow is initiated it can // Sign in with preferred challenge as password // NOTE: Password must be provided in the same step AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() - .callingActivity(activity) - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD" - .build(); + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD" + .build(); Amplify.Auth.signIn( username, password, @@ -335,10 +335,10 @@ Amplify.Auth.signIn( // Sign in with preferred passwordless challenge // No user input is required at this step AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() - .callingActivity(activity) - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP" - .build(); + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP" + .build(); Amplify.Auth.signIn( username, null, @@ -436,10 +436,10 @@ try { // Sign in with preferred challenge as password // NOTE: Password must be provided in the same step AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() - .callingActivity(activity) - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD" - .build(); + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD" + .build(); RxAmplify.Auth.signIn(username, password, options) .subscribe( result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), @@ -450,10 +450,10 @@ RxAmplify.Auth.signIn(username, password, options) // Sign in with preferred passwordless challenge // No user input is required at this step AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() - .callingActivity(activity) - .authFlowType(AuthFlowType.USER_AUTH) - .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP" - .build(); + .callingActivity(activity) + .authFlowType(AuthFlowType.USER_AUTH) + .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP" + .build(); RxAmplify.Auth.signIn(username, null, options) .subscribe( result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), @@ -473,8 +473,8 @@ The selection of the authentication method is done by the user. The user can cho ```java AuthConfirmSignInOptions options = AWSCognitoAuthConfirmSignInOptions.builder() - .callingActivity(activity) - .build(); + .callingActivity(activity) + .build(); Amplify.Auth.confirmSignIn( AuthFactorType.WEB_AUTHN.getChallengeResponse(), options, @@ -521,8 +521,8 @@ try { ```java AuthConfirmSignInOptions options = AWSCognitoAuthConfirmSignInOptions.builder() - .callingActivity(activity) - .build(); + .callingActivity(activity) + .build(); RxAmplify.Auth.confirmSignIn(AuthFactorType.WEB_AUTHN.getChallengeResponse(), options) .subscribe( result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), @@ -546,8 +546,8 @@ When you have migrated all your users, switch flows to the more secure SRP flow. ```java AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) - .build(); + .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) + .build(); Amplify.Auth.signIn( "username", "password", @@ -601,8 +601,8 @@ try { ```java AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() - .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) - .build(); + .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) + .build(); RxAmplify.Auth.signIn("username", "password", options) .subscribe( result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), From 11157701bd7c0cb454a2664493d4bd053a766c24 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Wed, 27 Nov 2024 15:26:57 -0800 Subject: [PATCH 13/19] Add first factor selection section for android after merge --- .../connect-your-frontend/sign-in/index.mdx | 174 +++++++++++++++--- 1 file changed, 145 insertions(+), 29 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index 342d78b5312..178b16d10fe 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -1711,35 +1711,6 @@ if (confirmSignInNextStep.signInStep === 'DONE') { console.log('Sign in successful!'); } ``` - - -### First Factor Selection - -Omit the `preferredChallenge` parameter to discover what first factors are available for a given user. - -The `confirmSignIn` API can then be used to select a challenge and initiate the associated authentication flow. - -```ts -const { nextStep: signInNextStep } = await signIn({ - username: '+15551234567', - options: { - authFlowType: 'USER_AUTH', - }, -}); - -if ( - signInNextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION' -) { - // present user with list of available challenges - console.log(`Available Challenges: ${signInNextStep.availableChallenges}`); - - // respond with user selection using `confirmSignIn` API - const { nextStep: nextConfirmSignInStep } = await confirmSignIn({ - challengeResponse: 'SMS_OTP', // or 'EMAIL_OTP', 'WEB_AUTHN', 'PASSWORD', 'PASSWORD_SRP' - }); -} - -``` @@ -1844,4 +1815,149 @@ RxAmplify.Auth.confirmSignIn("password") + +### First Factor Selection + +Omit the `preferredChallenge` parameter to discover what first factors are available for a given user. + +The `confirmSignIn` API can then be used to select a challenge and initiate the associated authentication flow. + + + +```ts +const { nextStep: signInNextStep } = await signIn({ + username: '+15551234567', + options: { + authFlowType: 'USER_AUTH', + }, +}); + +if ( + signInNextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION' +) { + // present user with list of available challenges + console.log(`Available Challenges: ${signInNextStep.availableChallenges}`); + + // respond with user selection using `confirmSignIn` API + const { nextStep: nextConfirmSignInStep } = await confirmSignIn({ + challengeResponse: 'SMS_OTP', // or 'EMAIL_OTP', 'WEB_AUTHN', 'PASSWORD', 'PASSWORD_SRP' + }); +} + +``` + + + + + + +```java +// Retrieve the authentication factors by calling .availableFactors +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build(); +Amplify.Auth.signIn( + "username", + null, + options, + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { + Log.i( + "AuthQuickstart", + "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors() + ); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) +); +``` + + + + +```kotlin +// Retrieve the authentication factors by calling .availableFactors +val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build() +Amplify.Auth.signIn( + "username", + null, + options, + { result -> + if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { + Log.i( + "AuthQuickstart", + "Available factors for this user: ${result.nextStep.availableFactors}" + ) + } + }, + { error -> + Log.e("AuthQuickstart", "Failed to sign in", error) + } +) +``` + + + + +```kotlin +try { + // Retrieve the authentication factors by calling .availableFactors + val options = AWSCognitoAuthSignInOptions.builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build() + val result = Amplify.Auth.signIn( + username = "username", + password = null, + options = options + ) + if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { + Log.i( + "AuthQuickstart", + "Available factors for this user: ${result.nextStep.availableFactors}" + ) + } +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign in failed", error) +} +``` + + + + +```java +// Retrieve the authentication factors by calling .availableFactors +AWSCognitoAuthSignInOptions options = + AWSCognitoAuthSignInOptions + .builder() + .authFlowType(AuthFlowType.USER_AUTH) + .callingActivity(callingActivity) + .build(); +RxAmplify.Auth.signIn("username", null, options) + .subscribe( + result -> { + if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { + Log.i( + "AuthQuickstart", + "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors() + ); + } + }, + error -> Log.e("AuthQuickstart", error.toString()) + ); +``` + + + + + + + + From 2541ee1d409cf3babf5cbc18c38fbf456aba3c20 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 29 Nov 2024 10:17:03 -0800 Subject: [PATCH 14/19] Update src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx Co-authored-by: josef --- .../auth/connect-your-frontend/multi-step-sign-in/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx index 8420a40d3e0..771a3ec3333 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx @@ -1506,7 +1506,7 @@ If the next step is `CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE`, Amplify Auth has sent t -The result result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial phone number of the SMS recipient. +**Note:** The result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial phone number of the SMS recipient. From b12eda570cdee4980491854f8f1294eeec746b05 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 29 Nov 2024 10:17:20 -0800 Subject: [PATCH 15/19] Update src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx Co-authored-by: josef --- .../auth/connect-your-frontend/multi-step-sign-in/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx index 771a3ec3333..b37ac1a69cc 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx @@ -1617,7 +1617,7 @@ If the next step is `CONFIRM_SIGN_IN_WITH_EMAIL_MFA_CODE`, Amplify Auth has sent -The result result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial email address of the recipient. +**Note:** The result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial email address of the recipient. From d77e718cddadc351120eeddc705f557e088432de Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 29 Nov 2024 10:20:53 -0800 Subject: [PATCH 16/19] Apply suggestions from code review Co-authored-by: josef --- .../auth/connect-your-frontend/multi-step-sign-in/index.mdx | 4 ++-- .../auth/connect-your-frontend/sign-up/index.mdx | 2 +- .../switching-authentication-flows/index.mdx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx index b37ac1a69cc..b6f8d89bcbb 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx @@ -1627,7 +1627,7 @@ If the next step is `CONFIRM_SIGN_IN_WITH_OTP`, Amplify Auth has sent the user a -The result includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery, such as the partial email address of the recipient, which can be used to prompt the user on where to look for the code. +**Note:** The result includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery, such as the partial email address of the recipient, which can be used to prompt the user on where to look for the code. @@ -1998,7 +1998,7 @@ This call fetches the current logged in user and should be used after a user has If the user is signed in, it will return the current userId and username. -An empty string will be assigned to userId and/or username, if the values are not present in the accessToken. +**Note:** An empty string will be assigned to userId and/or username, if the values are not present in the accessToken. diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx index 6f52c51d93f..c3655f4f8cd 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx @@ -893,7 +893,7 @@ if (confirmSignUpNextStep.signUpStep === 'DONE') { ```java // Sign up using an email address ArrayList attributes = new ArrayList<>(); -attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com")); +attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "hello@example.com")); Amplify.Auth.signUp( "username", diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index 92af8979bcb..ef4f97e0377 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -299,7 +299,7 @@ Runtime configuration will take precedence and will override any auth flow type -> For more information about authentication flows, please visit [Amazon Cognito developer documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow) +For more information about authentication flows, please visit [Amazon Cognito developer documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow) ## USER_AUTH (Choice-based authentication) flow From 6f26a46eb4ce9966b50cb326827b1c41d6d23dc6 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 29 Nov 2024 10:27:55 -0800 Subject: [PATCH 17/19] Replace usages of username with email --- .../multi-step-sign-in/index.mdx | 8 ++--- .../connect-your-frontend/sign-in/index.mdx | 8 ++--- .../connect-your-frontend/sign-up/index.mdx | 34 +++++++++---------- .../switching-authentication-flows/index.mdx | 12 +++---- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx index b6f8d89bcbb..d19dc10329e 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx @@ -1068,7 +1068,7 @@ The `nextStep` property is of enum type `AuthSignInStep`. Depending on its value ```java try { Amplify.Auth.signIn( - "username", + "hello@example.com", "password", result -> { @@ -1184,7 +1184,7 @@ try { ```kotlin try { Amplify.Auth.signIn( - "username", + "hello@example.com", "password", { result -> val nextStep = result.nextStep @@ -1291,7 +1291,7 @@ try { ```kotlin try { val result = Amplify.Auth.signIn( - "username", + "hello@example.com", "password" ) val nextStep = result.nextStep @@ -1391,7 +1391,7 @@ try { ```java -RxAmplify.Auth.signIn("username", "password").subscribe( +RxAmplify.Auth.signIn("hello@example.com", "password").subscribe( result -> { AuthNextSignInStep nextStep = result.getNextStep(); diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index 178b16d10fe..49814c6daaa 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -1860,7 +1860,7 @@ AWSCognitoAuthSignInOptions options = .callingActivity(callingActivity) .build(); Amplify.Auth.signIn( - "username", + "hello@example.com", null, options, result -> { @@ -1885,7 +1885,7 @@ val options = AWSCognitoAuthSignInOptions.builder() .callingActivity(callingActivity) .build() Amplify.Auth.signIn( - "username", + "hello@example.com", null, options, { result -> @@ -1913,7 +1913,7 @@ try { .callingActivity(callingActivity) .build() val result = Amplify.Auth.signIn( - username = "username", + username = "hello@example.com", password = null, options = options ) @@ -1939,7 +1939,7 @@ AWSCognitoAuthSignInOptions options = .authFlowType(AuthFlowType.USER_AUTH) .callingActivity(callingActivity) .build(); -RxAmplify.Auth.signIn("username", null, options) +RxAmplify.Auth.signIn("hello@example.com", null, options) .subscribe( result -> { if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) { diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx index c3655f4f8cd..f06dcbdb8bc 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx @@ -587,7 +587,7 @@ ArrayList attributes = new ArrayList<>(); attributes.add(new AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567")); Amplify.Auth.signUp( - "username", + "hello@example.com", null, AuthSignUpOptions.builder().userAttributes(attributes).build(), result -> { @@ -605,7 +605,7 @@ Amplify.Auth.signUp( // Confirm sign up with the OTP received Amplify.Auth.confirmSignUp( - "username", + "hello@example.com", "123456", result -> { if (result.isSignUpComplete()) { @@ -631,7 +631,7 @@ val options = .build() Amplify.Auth.signUp( - "username", + "hello@example.com", null, options, { result -> @@ -649,7 +649,7 @@ Amplify.Auth.signUp( // Confirm sign up with the OTP received Amplify.Auth.confirmSignUp( - "username", + "hello@example.com", "123456", { result -> if (result.nextStep.signUpStep == AuthSignUpStep.DONE) { @@ -673,7 +673,7 @@ val options = .builder() .userAttributes(attributes) .build() -var result = Amplify.Auth.signUp("username", null, options) +var result = Amplify.Auth.signUp("hello@example.com", null, options) if (result.isSignUpComplete) { Log.i("AuthQuickstart", "Sign up is complete") @@ -686,7 +686,7 @@ if (result.isSignUpComplete) { // Confirm sign up with the OTP received result = Amplify.Auth.confirmSignUp( - "username", + "hello@example.com", "123456" ) @@ -704,7 +704,7 @@ ArrayList attributes = new ArrayList<>(); attributes.add(new AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567")); RxAmplify.Auth.signUp( - "username", + "hello@example.com", null, AuthSignUpOptions.builder().userAttributes(attributes).build() ) @@ -724,7 +724,7 @@ RxAmplify.Auth.signUp( // Confirm sign up with the OTP received RxAmplify.Auth.confirmSignUp( - "username", + "hello@example.com", "123456" ) .subscribe( @@ -896,7 +896,7 @@ ArrayList attributes = new ArrayList<>(); attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "hello@example.com")); Amplify.Auth.signUp( - "username", + "hello@example.com", null, AuthSignUpOptions.builder().userAttributes(attributes).build(), result -> { @@ -914,7 +914,7 @@ Amplify.Auth.signUp( // Confirm sign up with the OTP received Amplify.Auth.confirmSignUp( - "username", + "hello@example.com", "123456", result -> { if (result.isSignUpComplete()) { @@ -940,7 +940,7 @@ val options = .build() Amplify.Auth.signUp( - "username", + "hello@example.com", null, options, { result -> @@ -958,7 +958,7 @@ Amplify.Auth.signUp( // Confirm sign up with the OTP received Amplify.Auth.confirmSignUp( - "username", + "hello@example.com", "123456", { result -> if (result.nextStep.signUpStep == AuthSignUpStep.DONE) { @@ -982,7 +982,7 @@ val options = .builder() .userAttributes(attributes) .build() -var result = Amplify.Auth.signUp("username", null, options) +var result = Amplify.Auth.signUp("hello@example.com", null, options) if (result.isSignUpComplete) { Log.i("AuthQuickstart", "Sign up is complete") @@ -995,7 +995,7 @@ if (result.isSignUpComplete) { // Confirm sign up with the OTP received result = Amplify.Auth.confirmSignUp( - "username", + "hello@example.com", "123456" ) @@ -1013,7 +1013,7 @@ ArrayList attributes = new ArrayList<>(); attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com")); RxAmplify.Auth.signUp( - "username", + "hello@example.com", null, AuthSignUpOptions.builder().userAttributes(attributes).build() ) @@ -1033,7 +1033,7 @@ RxAmplify.Auth.signUp( // Confirm sign up with the OTP received RxAmplify.Auth.confirmSignUp( - "username", + "hello@example.com", "123456" ) .subscribe( @@ -1237,7 +1237,7 @@ fun autoSignIn() { suspend fun confirmSignUp(username: String, confirmationCode: String) { // Confirm sign up with the OTP received then auto sign in val result = Amplify.Auth.confirmSignUp( - "username", + "hello@example.com", "123456" ) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index ef4f97e0377..4c4c3f8f676 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -399,7 +399,7 @@ try { .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD" .build() val result = Amplify.Auth.signIn( - username = "username", + username = "hello@example.com", password = "password", options = options ) @@ -418,7 +418,7 @@ try { .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP" .build() val result = Amplify.Auth.signIn( - username = "username", + username = "hello@example.com", password = null, options = options ) @@ -549,7 +549,7 @@ AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) .build(); Amplify.Auth.signIn( - "username", + "hello@example.com", "password", options, result -> Log.i("AuthQuickStart", "Sign in succeeded with result " + result), @@ -565,7 +565,7 @@ val options = AWSCognitoAuthSignInOptions.builder() .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) .build() Amplify.Auth.signIn( - "username", + "hello@example.com", "password", options, { result -> @@ -586,7 +586,7 @@ try { .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) .build() val result = Amplify.Auth.signIn( - username = "username", + username = "hello@example.com", password = "password", options = options ) @@ -603,7 +603,7 @@ try { AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder() .authFlowType(AuthFlowType.USER_PASSWORD_AUTH) .build(); -RxAmplify.Auth.signIn("username", "password", options) +RxAmplify.Auth.signIn("hello@example.com", "password", options) .subscribe( result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()), error -> Log.e("AuthQuickstart", error.toString()) From a432cb35f6cd26e842e384eaae9dc80b0450a511 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 29 Nov 2024 10:33:49 -0800 Subject: [PATCH 18/19] Update src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx Co-authored-by: James Jarvis --- .../build-a-backend/auth/connect-your-frontend/sign-in/index.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index 49814c6daaa..59c955c5fee 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -847,7 +847,6 @@ await autoSignIn(); -To sign in using an external identity provider such as Google, use the `signInWithRedirect` function. ### Install native module From 23575cd7f3b97d4f1e698298fababcea82943916 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 29 Nov 2024 14:58:00 -0800 Subject: [PATCH 19/19] Update index.mdx --- .../switching-authentication-flows/index.mdx | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx index 4c4c3f8f676..f0bcbe79167 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/index.mdx @@ -102,30 +102,6 @@ func signIn(username: String, password: String) async throws { } ``` -### Set up auth backend - -In order to use the authentication flow `USER_PASSWORD_AUTH`, your Cognito app client has to be configured to allow it. Amplify Gen 2 enables SRP auth by default. To enable USER_PASSWORD_AUTH, you can update the `backend.ts` file with the following changes: - -```ts title="amplify/backend.ts" -import { defineBackend } from '@aws-amplify/backend' -import { auth } from './auth/resource' -import { data } from './data/resource' - -const backend = defineBackend({ - auth, - data, -}); - -// highlight-start -backend.auth.resources.cfnResources.cfnUserPoolClient.explicitAuthFlows = [ - "ALLOW_USER_PASSWORD_AUTH", - "ALLOW_USER_SRP_AUTH", - "ALLOW_USER_AUTH", - "ALLOW_REFRESH_TOKEN_AUTH" -]; -// highlight-end -``` - ### Migrate users with Amazon Cognito Amazon Cognito provides a trigger to migrate users from your existing user directory seamlessly into Cognito. You achieve this by configuring your User Pool's "Migration" trigger which invokes a Lambda function whenever a user that does not already exist in the user pool authenticates, or resets their password.