Add A Cognito PreSignUp Lambda Trigger via Amplify in NET Core

We are going to add a Cognito PreSignUp trigger to an existing Cognito Pool from Amplify with a .NET Lambda. Took me a while to figure that out too.

You’ve got an AWS Cognito Identity Pool. You’re building an app and somewhere sits Amplify. You’re writing your Lambda’s in .NET Core. I’ve been doing it for a while now, I wrote about scheduling Lambda’s.

You suddenly have a requirement from somebody that requires the use of PreSignUp but you don’t know how to add it? From what I can tell, doing this is not exactly easy and

Let’s figure this out. There may well be a way to do this without following this page but if there is, I could not find it. I also strongly suggest you take a backup, a new branch and get your mother on speed dial.

1. Setup a Lambda function

Run this

amplify function add

Now answer the questions:

? Select which capability you want to add: Lambda function (serverless function)
 ? Provide an AWS Lambda function name: MyAppPreSignUp
 ? Choose the runtime that you want to use: .NET Core 3.1
 ? Choose the function template that you want to use: Hello World
 Available advanced settings:
 Resource access permissions
 Scheduled recurring invocation
 Lambda layers configuration 
 ? Do you want to configure advanced settings? No
 ? Do you want to edit the local lambda function now? No
 Successfully added resource MyAppPreSignUp locally.

Run and update your resources, remember the function name.

amplify push

3. Now the tricky bit: Update Cognito.

Now we need to tell Cognito to use the PreSignUp Lambda. Lets go.

Run

amplify auth update

Answer the questions. Lots of questions. It’s important that when you’re asked the following questions you select the options that are right for you. These should be the same as they where when you first ran this.

What do you want to do? Walkthrough all the auth configurations
  Select the authentication/authorization services that you want to use: User Sign-Up, Sign-In, connected with AWS IAM controls (Enables per-user Storage features for images or other content, Analytics, and more)
  Allow unauthenticated logins? (Provides scoped down permissions that you can control via AWS IAM) No
  Do you want to enable 3rd party authentication providers in your identity pool? No
  Do you want to add User Pool Groups? No
  Do you want to add an admin queries API? No
  Multifactor authentication (MFA) user login options: OFF
  Email based user registration/forgot password: Enabled (Requires per-user email entry at registration)
  Please specify an email verification subject: Your verification code
  Please specify an email verification message: Your verification code is {####}
  Do you want to override the default password policy for this User Pool? No
  Specify the app's refresh token expiration period (in days): 30
  Do you want to specify the user attributes this app can read and write? No
  Do you want to enable any of the following capabilities? 
  Do you want to use an OAuth flow? No

Now stop. The next question, answer YES

? Do you want to configure Lambda Triggers for Cognito? Yes

This question has about 10 options so scroll down until you see “Pre Sign-Up” and when it’s highlighted select it. Then press return. In the next question, select the last option (as shown below).

? What functionality do you want to use for Pre Sign-up
◯ Learn More
──────────────
❯◯ Sign-Up email filtering (whitelist)
◯ Sign-Up email filtering (blacklist)
◉ Create your own module

You’ll see a bunch of notes about your new function. Make a note of the function name

Check out sample function code generated in <project-dir>/amplify/backend/function/myapp9a611b04PreSignup/src

We need to make a note of "myapp9a611b04PreSignup". Carry on answering the questions.

? Do you want to edit your custom function now? (Y/n) n

After this, amplify should exit.

What mess have we made? I don’t know why Amplify here, doesn’t replicate the same behaviour as amplify function add and give you a language choice.

3. Update our backend

Now we need to go and edit our backend-config.json. Go open that in an editor of your choice and find the “auth” section.

Note: We are going to do some find and replace here, everything is case sensitive.

"auth": {
     "<cognito pool name>": {
       "service": "Cognito",
       "providerPlugin": "awscloudformation",
       "dependsOn": [
         {
           "category": "function",
           "resourceName": "myapp9a611b04PreSignup",
           "triggerProvider": "Cognito",
           "attributes": [
             "Arn",
             "Name"
           ]
         }
       ],
       "customAuth": false
     }
   },

See that bit where it says "myapp9a611b04PreSignup". Change that to the name of function you made in step 1, in our case: MyAppPreSignUp.

Now in backend/auth/<cognito pool name> folder there is a yml file. Open that and do a find and on the 2 names. Replace myapp9a611b04PreSignup with MyAppPreSignUp. Save and close.

In the same folder as the yml file, there is a parameters.json, open that and repeat. Save and close.

Now go and find amplify-meta.json and do the same. There should be only one reference here.

"auth": {
     "<Cognito Pool Name>": {
       "service": "Cognito",
       "providerPlugin": "awscloudformation",
       "dependsOn": [
         {
           "category": "function",
           "resourceName": "myapp9a611b04PreSignup ",
           "triggerProvider": "Cognito",
           "attributes": [
             "Arn",
             "Name"
           ]
         }
       ],

Save and close.

4. Remove the AWS generated function from Amplify and CloudFormation templates.

Run this

amplify function remove myapp9a611b04PreSignup

If you get an error like this below, you missed a reference to the generated function. Go back and look again.

Resource cannot be removed because it has a dependency on another resource
 Dependency: Cognito:myapp9a611b04
 Error: Resource cannot be removed because it has a dependency on another resource
     at /usr/local/lib/node_modules/@aws-amplify/cli/lib/extensions/amplify-helpers/remove-resource.js:128:31
     at Array.forEach (<anonymous>)
     at /usr/local/lib/node_modules/@aws-amplify/cli/lib/extensions/amplify-helpers/remove-resource.js:124:40
     at Array.forEach (<anonymous>)
     at deleteResourceFiles (/usr/local/lib/node_modules/@aws-amplify/cli/lib/extensions/amplify-helpers/remove-resource.js:122:22)
     at runMicrotasks (<anonymous>)
     at processTicksAndRejections (internal/process/task_queues.js:93:5)
     at async Object.executeAmplifyCommand (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-category-function/lib/index.js:201:5)
     at async executePluginModuleCommand (/usr/local/lib/node_modules/@aws-amplify/cli/lib/execution-manager.js:166:5)
     at async Object.executeCommand (/usr/local/lib/node_modules/@aws-amplify/cli/lib/execution-manager.js:35:9)
 An error occurred when removing the function resource

Now run amplify push and push your updates. Wait, we didn’t update the .NET Lambda function for the pre auth! Amazon have the PreSignUp flows documented.

Errors

If you start getting this kind of error:

⠋ Updating resources in the cloud. This may take a few minutes…Error: Profile configuration is missing for: amp
     at Object.getProfiledAwsConfig (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-provider-awscloudformation/src/system-config-manager.js:90:17)
     at loadConfigurationForEnv (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-provider-awscloudformation/src/configuration-manager.ts:568:45)
     at runMicrotasks ()
     at processTicksAndRejections (internal/process/task_queues.js:93:5)
     at Object.loadConfiguration (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-provider-awscloudformation/src/configuration-manager.ts:524:18)
     at Object.aws.configureWithCreds (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-provider-awscloudformation/src/aws-utils/aws.js:30:18)
     at Object.getConfiguredAWSClient (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-provider-awscloudformation/src/index.ts:67:3)
     at getS3Client (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-category-auth/src/provider-utils/awscloudformation/utils/trigger-file-uploader.js:13:15)
     at uploadFiles (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-category-auth/src/provider-utils/awscloudformation/utils/trigger-file-uploader.js:19:22)
 ✖ An error occurred when pushing the resources to the cloud
 Unable to upload trigger files to S3
 An error occurred during the push operation: Unable to upload trigger files to S3

Then run amplify configure and reset your profile, mine had issues due to the ~/aws/credentials file being messed up adding another profile.

If you get this Resource cannot be removed because it has a dependency on another resource Dependency: Cognito:myapp9a611b04. Then your Cognito definition still references the old function

All done & PreSignUp is implemented

Now after all of that, you can get to actually implementing your PreSignUp trigger and do what you need.

You can use this little snippet below just as a temporary holder to act as a pass through. Cognito expects you to send back the object you got sent with some modifications in place

public async Task LambdaHandler(JObject input, ILambdaContext context)
{
    context.Logger.LogLine($"Received data: {Newtonsoft.Json.JsonConvert.SerializeObject(input)}");
    return input;
}

JObject will have the request information and you can send your results by modify that object and returning it.

Comments