amplify-js icon indicating copy to clipboard operation
amplify-js copied to clipboard

PreAuthentication trigger not triggered in Custom Auth Flow

Open armandabric opened this issue 4 years ago • 41 comments

** Which Category is your question related to? ** Auth

** What AWS Services are you utilizing? ** Cognito

** Provide additional details e.g. code snippets **

I have an issue with the Cognito PreAuthentication trigger not triggered when an user sign-in

We are using a Cognito user pool with only CUSTOM_AUTH_FLOW_ONLY auth to do a passwordless authentication system.

I my CloudFormation template I have configured a lambda to handle the trigger :

  # ...

  PreAuthentication:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/lambda-triggers/pre-authentication/
      Handler: pre-authentication.handler
      Runtime: nodejs12.x

  # ...

PreAuthenticationInvocationPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt PreAuthentication.Arn
      Principal: cognito-idp.amazonaws.com
      SourceArn: !GetAtt UserPool.Arn

  # ... 

  UserPool:
    Type: "AWS::Cognito::UserPool"
    Properties:
      UserPoolName: !Ref UserPoolName
      Schema: # ...
      Policies: # ...
      UsernameAttributes:
        - email
      MfaConfiguration: "OFF"
      LambdaConfig:
        CreateAuthChallenge: !GetAtt CreateAuthChallenge.Arn
        DefineAuthChallenge: !GetAtt DefineAuthChallenge.Arn
        PreSignUp: !GetAtt PreSignUp.Arn
        PreAuthentication: !GetAtt PreAuthentication.Arn # Here 
        VerifyAuthChallengeResponse: !GetAtt VerifyAuthChallengeResponse.Arn
        PostAuthentication: !GetAtt PostAuthentication.Arn

# ...

  UserPoolClient:
    Type: "AWS::Cognito::UserPoolClient"
    Properties:
      ClientName: email-auth-client
      GenerateSecret: false
      UserPoolId: !Ref UserPool
      ExplicitAuthFlows:
        - CUSTOM_AUTH_FLOW_ONLY

For now the lambda implementation is useless:

import { CognitoUserPoolTriggerHandler } from "aws-lambda";

export const handler: CognitoUserPoolTriggerHandler = async (
  event,
  context
) => {
  console.log(event, context);

  // return event;
  throw new Error("Is this really executed?");
};

When I deploy the lambda it appear correctly in the Cognito UI as the registered trigger.

But impossible to have the function to be executed on sign in (nor sign up):

const newCognitoUser = await AmplifyAuth.signIn({
    username: email,
    password: "",
    validationData: { some_data: "foo_bar" },
});

# No PreAuthentication lambda triggered
# Others triggers works perfectly.

Is this an issue Aplify or is that an issue with my understanding of the auth process?

armandabric avatar Apr 07 '20 13:04 armandabric

Have you tried utilizing the Amplify CLI to configure Cognito with a Lambda trigger?

iartemiev avatar Apr 16 '20 18:04 iartemiev

I did not have try the Amplify Cli but the Cognito GUI and Cloud Formation deployment template. Is the CLI is mandatory?

armandabric avatar Apr 17 '20 10:04 armandabric

Hi @Spy-Seth - the CLI flow is recommended. You could spin up a sample project with the CLI and let us know if that works? This will help determine if it's a potential issue. This doc will help you get started -> https://docs.amplify.aws/cli/usage/lambda-triggers#cognito-lambda-triggers

mauerbac avatar Apr 24 '20 18:04 mauerbac

@mauerbac I work with @Spy-Seth and we have an example repository to reproduce the issue.

BTW we've not used Amplify CLI here but terraform. At the end it's the very same I guess. We've also used a cognito cloudformation stack in another try and every time we have this same issue with the never invoked pre authentication lambda.

Could it be related to auth flows we allow?

shouze avatar Apr 24 '20 20:04 shouze

@shouze can you see the validationData as part of the data request?

elorzafe avatar Apr 24 '20 22:04 elorzafe

@shouze : I dont see how the validationData is being passed in. From the code, I only see email is sent in.

For pre authentication or pre sign up, it is important to pass in validationData - https://docs.amplify.aws/lib/auth/advanced/q/platform/js#pre-authentication-and-pre-sign-up-lambda-triggers

ashika01 avatar Apr 24 '20 22:04 ashika01

@ashika01 ok yes will try that, If I remember well we've already tried and that didn't works but I prefer to double check.

shouze avatar Apr 27 '20 15:04 shouze

@shouze yeah let us know how it goes.

ashika01 avatar Apr 27 '20 22:04 ashika01

@ashika01 I've tried with no more luck (I've tried both variants with username as a string and validation data as third argument, validation data in signinOpts as first argument, nor more arguments) https://github.com/Spy-Seth/cognito-passwordless-bug/commit/d0be033d9f987d125ffed5344a955e684223f7f0#diff-da5998deda0a56bb613b4fe12ae4eef9R22-R29

Moreover I can confirm you that my browser network inspector as the proof that the payload effectively contains validation data (but, transformed as client metadata): image

as I have it as validationData until initiateAuth get called into the debugger: image

transformed/normalized later on: image

Here it was just about the signin part, same thing with signup.

shouze avatar Apr 28 '20 08:04 shouze

According to the doc this normalization sounds OK https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html#API_InitiateAuth_RequestSyntax

shouze avatar Apr 28 '20 08:04 shouze

On my side, impossible to have preAuth Working It prevents the logging leaving no trace in cognito, no log log for the Lambda like if it was never called I enable preAuthTrigger through CloudFormation the code now is the sample from the doc :

exports.handler = async (event, context, callback) => {

    if (event.callerContext.clientId === "user-pool-app-client-id-to-be-blocked") {

        var error = new Error("Cannot authenticate users from this user pool app client");

        // Return error to Amazon Cognito

        callback(error, event);

    }

    // Return to Amazon Cognito

    callback(null, event);
};

The lambda is defined and exported in a CDK Stack The Userpool is defined and its triigered attached in cloud Formation PosAuth works fine BTW the lambda works fine tested from lambda console

Very annoying

Chewbee avatar May 13 '20 21:05 Chewbee

After contacting the AWS support it's a know bug: the pre-authentification hook is not called on custom auth flow

armandabric avatar May 14 '20 08:05 armandabric

Would be nice to see it fixed though

shouze avatar May 14 '20 13:05 shouze

I can confirm this is not an issue with Amplify library, is a restriction by Cognito User Pools.

Why do you need validation data and custom challenge, those seems to be similar to me. Maybe I am missing another use case.

Thanks

elorzafe avatar May 15 '20 01:05 elorzafe

@Spy-Seth have you heard more regarding the bug? I am also finding that the pre-authentication trigger is not called while using custom auth flow. This was the only thread I could on the topic so far.

rennehir avatar Jun 29 '20 11:06 rennehir

@reedyrm We have no news about this bug. We are waiting to see if this bug is resolved

@elorzafe I miss your message sorry. We a are looking to inject validation data (a token in our case) in the login process to be able to open the passwordless link in another device than the one than generate it: start to use you mobile, check your mail on the desktop and click on it, and get back back to the same point.

armandabric avatar Jul 01 '20 07:07 armandabric

here is the way, how I did multienv support:




  "Conditions": {

    "CurrentEnvIsLive": {

      "Fn::Equals": [

        {

          "Ref": "env"

        },

        "live"

      ]

    }

    ....

  },



.....



        "VpcConfig": {

          "Fn::If": [

            "CurrentEnvIsLive",

            {

              "SecurityGroupIds": [

                "sg-xx"

              ],

              "SubnetIds": [

                "subnet-xxx"

              ]

            },

            {

              "SecurityGroupIds": [

                "sg-yy"

              ],

              "SubnetIds": [

                "subnet-yyy"

              ]

            }

          ]

        },





Are you sure this is related to current topic

shouze avatar Sep 10 '20 18:09 shouze

This bug is killing us. We use a custom cognito authentication flow (magic links) and we wanted to allow our users to choose to get their magic link via email or sms. We wanted to use ClientMetadata from Auth.signIn in order to convey the information {sendLinkViaSms: boolean} so that our custom lambdas know wether to send an email or a SMS.

The only trigger called with ClientMetadata on InitiateAuth is PreAuthentication (documented here). Our plan was to update a user custom attribute with this information, so that the trigger responsible to send the magic link (CreateAuthChallenger) could read that info and send the message on the approriate channel.

But with this bug, we have no way of transmitting business logic information from the user to the cognito triggers, seriously limiting our feature development capabilities.

mmeylan avatar Oct 09 '20 13:10 mmeylan

This bug is killing us. We use a custom cognito authentication flow (magic links) and we wanted to allow our users to choose to get their magic link via email or sms. We wanted to use ClientMetadata from Auth.signIn in order to convey the information {sendLinkViaSms: boolean} so that our custom lambdas know wether to send an email or a SMS.

The only trigger called with ClientMetadata on InitiateAuth is PreAuthentication (documented here). Our plan was to update a user custom attribute with this information, so that the trigger responsible to send the magic link (CreateAuthChallenger) could read that info and send the message on the approriate channel.

But with this bug, we have no way of transmitting business logic information from the user to the cognito triggers, seriously limiting our feature development capabilities.

@mmeylan we are exactly in the same situation! You've made a very good summary of the situation :heart:. As we're not live in production yet on our side... it's ok-ish. We have alternatives in mind like Auth0 or NextAuth or even Symfony 5.2 incoming magic link.

@elorzafe is it planned at some point to fix it? Is it in any roadmap? Documentation should be at least updated to warn that it's a dead end for every people that try to implement magic links no? Especially since this post has been published more than 1 year ago. The related github repository had some mark of interest (> 100 stars & probably a magnitude of interested people that have not starred it).

shouze avatar Oct 09 '20 13:10 shouze

All thank you for the feedback in regards to this. As @elorzafe has callout, this issue is not related to Amplify and more so for Amazon Cognito. Amplify is used as a proxy to AWS resources such as Amazon Cognito. We will look to talk to them internally about this however, I do recommend reaching out to Amazon Cognito via their forums.

sammartinez avatar Oct 09 '20 15:10 sammartinez

@sammartinez copy that, so we can close this issue @Spy-Seth. We are agree, this is pure Cognito issue, not Amplify related.

I've found a related thread on Cognito forum, other people that reproduces but not answered. So if you can internally do something :pray: passwordless is a big trend at the moment (as WebAuthn will probably be the next one).

shouze avatar Oct 09 '20 16:10 shouze

Do you have some updates guys?

R-iskey avatar Jul 15 '21 10:07 R-iskey

I got this from AWS support today (almost 2 years after this issue was open):

Thanks for your patience. I can confirm that the service team is still working on the request to invoke preAuth trigger when custom auth flow is used. I have added your case to the request to better prioritize the development. I am checking if there is a workaround on this.

I see that the preAuth Lambda will be triggered only if PASSWORD_VERIFIER challenge is used as the first challenge in the custom auth flow.

campidelli avatar Nov 01 '21 02:11 campidelli

Hit this issue as well.. Would love to see this issue get fixed as it's also impacting my passwordless workflow.

richmengsix avatar Feb 22 '22 21:02 richmengsix

Same here, any updates on when this could be fixed?

lukasburns avatar Apr 27 '22 18:04 lukasburns

Is there any development on this issue?

ayushman2001 avatar Sep 26 '22 07:09 ayushman2001

This bug is killing us. We use a custom cognito authentication flow (magic links) and we wanted to allow our users to choose to get their magic link via email or sms. We wanted to use ClientMetadata from Auth.signIn in order to convey the information {sendLinkViaSms: boolean} so that our custom lambdas know wether to send an email or a SMS.

The only trigger called with ClientMetadata on InitiateAuth is PreAuthentication (documented here). Our plan was to update a user custom attribute with this information, so that the trigger responsible to send the magic link (CreateAuthChallenger) could read that info and send the message on the approriate channel.

But with this bug, we have no way of transmitting business logic information from the user to the cognito triggers, seriously limiting our feature development capabilities.

any news on this? :)

WillUK99 avatar Feb 02 '23 15:02 WillUK99

any update on it?

I implemented custom challenge mode to add passwordless login with sms-code and wanted to prevent fraud sms sending in case recaptcha is missing (sms is sent in create challenge trigger) . the only trigger that seems to fit this purpose is pre auth since it does have access to metadata that client can send, but this trigger is not called with custom challenge mode...

ghost avatar Feb 21 '23 12:02 ghost

Hey @mordechai-dror i have the same issue, did you figure out a workaround?

kelvin-iimmpact avatar Jun 28 '23 16:06 kelvin-iimmpact

@kelvin-iimmpact The current solution is that the client first goes to dynamodb table, where each user has its own account record, updates there the required metadata, and only after it sends auth request, so the custom challenge lambda can query dynamodb by cognito user sub/username and retrieve the metadata. it means that the init auth process is split into two separate requests, which is not perfect, but at least it works

ghost avatar Jun 29 '23 05:06 ghost