aws-amplify / amplify-flutter

A declarative library with an easy-to-use interface for building Flutter applications on AWS.
https://docs.amplify.aws
Apache License 2.0
1.3k stars 239 forks source link

How to pass SignInOptions to Authenticator v2? #5047

Open Amirkhon opened 1 week ago

Amirkhon commented 1 week ago

Description

In Amplify Gen 1 the value of authenticationFlowType from the Amplify configuration object is used as default if none provided when calling Amplify.Auth.signIn() but with Gen 2 it should be provided under options parameter. How to authenticationFlowType parameter through Authenticator?

Categories

Steps to Reproduce

  1. Setup custom auth flow
  2. Use custom auth flow example from https://github.com/aws-amplify/amplify-flutter/blob/main/packages/authenticator/amplify_authenticator/example/lib/customization/authenticator_with_custom_auth_flow.dart
  3. Press Sign In button

Expected: The Confirm sign in page is opened Actual: No password provided error is shown

Screenshots

No response

Platforms

Flutter Version

3.3.0

Amplify Flutter Version

2.1.0

Deployment Method

Amplify CLI

Schema

No response

tyllark commented 1 week ago

Hello @Amirkhon thank you for submitting this issue. We will look into this and get back to you!

tyllark commented 1 week ago

Hello @Amirkhon, we need to update the example you linked as it does not handle the gen 2 method for custom Auth flow. The SignInButton Widget does not support custom Auth flow, so you will need to create your own button widget that calls:

Amplify.Auth.signIn(
      username: 'username',
      options: SignInOptions(
        pluginOptions: CognitoSignInPluginOptions(
          authFlowType: AuthenticationFlowType.customAuthWithoutSrp,
        ),
      ),
    );

Please let us know if this answers your question!

Amirkhon commented 1 week ago

hi @tyllark I created custom SignInButton widget with that calls signIn as you mention, but getting NotAuthorizedServiceException { "message": "Incorrect username or password.", "underlyingException": "NotAuthorizedException {\n message=Incorrect username or password.,\n}" }

To add more context, I am trying to migrate a project with custom auth flow from Amplify Gen 1 to Gen 2.

Jordan-Nelson commented 1 week ago

@Amirkhon Do you use custom auth with SRP or custom auth without SRP (Do you require the user to enter a password separately from your custom auth flow)? If you use custom auth with SRP the options you should use are slightly different.

Amplify.Auth.signIn(
  username: 'username',
  password: 'passsword',
  options: SignInOptions(
    pluginOptions: CognitoSignInPluginOptions(
      authFlowType: AuthenticationFlowType.customAuthWithSrp,
    ),
  ),
);

Let me know if you have any other questions.

Amirkhon commented 1 week ago

@Jordan-Nelson I implemented passwordless authentication with OTP on Amplify Gen 1. User enters phone number, receives confirmation code in SMS and signs in. Authentication flow type is CUSTOM_AUTH and as I understand in Gen 2 I need to pass customAuthWithoutSrp. I checked events that come to cognito user pools define auth challenge lambda and session array is empty with Amplify Gen 2 and authentication flow type customAuthWithoutSrp, while with Gen 1 there is on session object. Maybe any Cognito user pool change is required.

Jordan-Nelson commented 1 week ago

@Amirkhon Can you share your Gen 2 auth resource.ts file?

Amirkhon commented 1 week ago

@Jordan-Nelson there is no auth resources.ts file, the project was initiated with Gen 1. It seems like there is no way to migrate the backend to Gen 2. Amplify Flutter Gen 2 will not work with backend Gen 1?

Jordan-Nelson commented 1 week ago

Hello @Amirkhon - Apologies for the misunderstanding. Amplify Flutter version 2 does work with Amplify Backend Gen 1. I am not sure what is causing the issue your are facing.

Can you confirm the NotAuthorizedServiceException is being thrown by Amplify.Auth.signIn() (not confirmSignIn or other apis)?

Amirkhon commented 1 week ago

@Jordan-Nelson here is a code snipped:

return await Amplify.Auth.signIn(username: phoneNumber,
  options: const SignInOptions(pluginOptions: 
    CognitoSignInPluginOptions(authFlowType: AuthenticationFlowType.customAuthWithoutSrp)
   )
);

I noticed that event that receives define auth challenge lambda doesn't have any session. When using Amplify Flutter Gen 1, there is one session in the first event.

With Amplify Flutter Gen 2:

{
  version: '1',
  region: 'us-east-1',
  userPoolId: 'us-east-1_xxxxxx',
  userName: '8ea0e068-9967-4401-87f1-fb92f36d6c35',
  callerContext: {
    awsSdkVersion: 'aws-sdk-unknown-unknown',
    clientId: '36hu1gls86trbtmh3hhld6kqoh'
  },
  triggerSource: 'DefineAuthChallenge_Authentication',
  request: {
    userAttributes: {
      sub: '8ea0e068-9967-4401-87f1-fb92f36d6c35',
      'cognito:user_status': 'CONFIRMED',
      'cognito:phone_number_alias': '+000000000000',
      phone_number_verified: 'true',
      phone_number: '+000000000000'
    },
    session: []
  },
  response: { challengeName: null, issueTokens: null, failAuthentication: null }
}

With Amplify Flutter Gen 1:

{
  version: '1',
  region: 'us-east-1',
  userPoolId: 'us-east-1_xxxxx',
  userName: '8ea0e068-9967-4401-87f1-fb92f36d6c35',
  callerContext: {
    awsSdkVersion: 'aws-sdk-unknown-unknown',
    clientId: '36hu1gls86trbtmh3hhld6kqoh'
  },
  triggerSource: 'DefineAuthChallenge_Authentication',
  request: {
    userAttributes: {
      sub: '8ea0e068-9967-4401-87f1-fb92f36d6c35',
      'cognito:user_status': 'CONFIRMED',
      'cognito:phone_number_alias': '+000000000000',
      phone_number_verified: 'true',
      phone_number: '+000000000000'
    },
    session: [ [Object] ]
  },
  response: { challengeName: null, issueTokens: null, failAuthentication: null }
}
Jordan-Nelson commented 3 days ago

@Amirkhon what 1.x version of Amplify Flutter are you using? Are you using the latest 1.x version (1.8.0)?

Jordan-Nelson commented 3 days ago

@Amirkhon Can you inspect the network traffic and see if the response from the call to InitiateAuth includes a value for "session" when using AuthenticationFlowType.customAuthWithoutSrp with Amplify Flutter v2?

I do see one potential difference between Amplify Flutter v1 and v2 that may be causing this, although I am unsure if this would be the cause. In Amplify Flutter v1 the Authenticator always provides a password when calling sign in. It defaults to an empty string if none is set. You can mimic this behavior in Amplify Flutter version 2 by using AuthenticationFlowType.customAuthWithSrp and providing an empty password. Can you update your sign in button callback to the code below and see if the behavior matches what you observe in Amplify Flutter version 1?

Amplify.Auth.signIn(
  username: '<user_phone_number_or_username>',
  password: '', // empty string
  options: SignInOptions(
    pluginOptions: CognitoSignInPluginOptions(
      authFlowType: AuthenticationFlowType.customAuthWithSrp,
    ),
  ),
);
Jordan-Nelson commented 3 days ago

@Amirkhon I think the reason you are not seeing the session parameter is due to the difference I noted above. Cognito provides an initial session parameter to the DefineAuthChallenge Lambda when using Custom Auth with SRP (see cognito docs for details).

When using the authenticator in Amplify Flutter version 1 Custom Auth was defaulting to Custom Auth with SRP since there was a non-null password (as the Authenticator was defaulting to an empty string). In version 2 you need to explicitly choose between customAuthWithSrp and customAuthWithoutSrp. If you want to mimic the exact behavior of version 1 would need to use customAuthWithSrp with an empty string for a password.

If you are seeing a NotAuthorizedServiceException when using customAuthWithoutSrp I think it is likely that your lambda triggers are set up to handle Custom Auth with SRP. If this is the case you could either continue to use customAuthWithSrp (I would consider this a work around) or update your lambda to handle Custom Auth without SRP. If you can share your define auth challenge lambda code I can try to give you more info on what changes might be needed.

Amirkhon commented 2 days ago

@Jordan-Nelson thank you for help. AuthenticationFlowType.customAuthWithSrp with empty password worked.

Jordan-Nelson commented 2 days ago

@Amirkhon I am glad that worked.

It sounds like this is working as expected then. To summarize - When using the Authenticator with Amplify Flutter v1 the custom auth flow (custom auth with SRP vs custom auth without SRP) was inferred. This is no longer the case. The auth mode needs to be provided explicitly in Amplify Flutter v2. It seems that the custom auth flow triggers you are using were built for custom auth with SRP so you will need to continue using custom auth with SRP unless you modify those custom auth triggers.

Let me know if you have other questions.