AWS Amplify | User Auth using DynamoDB + Cognito Post-confirmation Lambda Trigger & Exposing GraphQL API 🔐

Jul 20, 2021 3 min read
AWS Amplify | User Auth using DynamoDB + Cognito Post-confirmation Lambda Trigger & Exposing GraphQL API 🔐
This guide assumes you went through the initial setup using the Auth and API recommended there.

Architecture

User attempts to sign up in client, we sent that data to Amazon Cognito, the lambda function gets triggered and we push that data to DynamoDB having it synchronized with AppSync so admin users can do queries and other functions using GraphQL

Create Lambda trigger Function post sign up confirmation

The following steps assumes you have Amplify setup already locally, if not check here how.

Add User Authentication

Let's begin by updating our existing Auth withe amplify update auth, in the prompts choose:

  • 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? No
  • Enable 3rd party authentication? No
  • Do you want to add User Pool Groups? Yes
  • Provide a name for your user pool group: Admin
  • Do you want to add an admin queries API? No
  • Do you want to specify the user attributes this app can read and write? No
  • Do you want to use an OAuth flow? No
  • Do you want to configure Lambda Triggers for Cognito? Yes
  • Which triggers do you want to enable for Cognito?  Post Confirmation
  • What functionality do you want to use for Post Confirmation? Create your own module
  • Do you want to edit your custom function now? Y
  • Replace the code with this one:
var aws = require('aws-sdk')
var ddb = new aws.DynamoDB()

exports.handler = async (event, context) => {
  let date = new Date()
  if (event.request.userAttributes.sub) {
    let params = {
      Item: {
        // Items below that begin with __ are needed for DataStore. When you create an object in
        // DataStore for the first time, those fields are created automatically. If you don't have it when
        // you go update an item, it will throw and error.
        'id': { S: event.request.userAttributes.sub },  // This is the Sub ID from AuthCognitoIdentityProvider, useful to query current user
        '__typename': { S: 'User' },
        '_lastChangedAt': { N: date.valueOf().toString() },   // timestamp
        '_version': { N: '1' },                               // Every time this object gets modified, this version will increase, therefore we begin with 1
        'createdAt': { S: date.toISOString() },
        'updatedAt': { S: date.toISOString() },
        'email': { S: event.request.userAttributes.email },
      },
      TableName: process.env.USERTABLE
    }

    try {
      await ddb.putItem(params).promise()
      console.log("Success")
    } catch (err) {
      console.log("Error", err)
    }

    console.log("Success: Everything executed correctly")

  } else {
    console.log("Error: Nothing was written to DynamoDB")
  }
};

Press enter to continue on the terminal.

Update GraphQL API

Assuming you follow the steps on the previous guide to setup the API, let's update the schema as follow:

type User @model @auth(rules: [
    { allow: owner, ownerField: "id" }
  ]) {
  id: ID!
  name: String
  age: Int
}
  • Commit the changes: amplify push
  • Do amplify codegen models and amplify codegen

Modify lambda function

1- Now on the local terminal type amplify console and select "Console"
2- Click on API and then View in AppSync

3- Next, on the left side, select "Data Sources"

4- Copy the resource name of the Table "UserTable"
5- On the local terminal type: amplify update function and select the option to environment variables. Follow the prompts and add in the following:

Enter the environment variable name: USERTABLE
Enter the environment variable value: "the name you copied above from the resource name UserTable"

For more info on lambda functions check here.

6 - Checkout the changes: amplify push -y

7- Click on Permissions in the lambda function and click the link under Execution role. Here we'll be giving permission to our lambda function to interact with our DynamoDB.
8- Click on "Add inline policy" and select JSON to only allow DynamoDB Put action.

Copy paste the following:

Note: to get your dynamodb resource below, go to the same section in step 3 above and click the link on Data Source -> Under Resource, the unfold Additional info
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:PutItem"
            ],
            "Resource": "DYANMODB_USER_ARN_GOES_HERE"
        }
    ]
}

9- Click review policy and give it a name such as "dynamoDbPutItemFromLambda"

Next steps:

Go to the User Pool you are using and make sure you have email verification on. After that pull the changes amplify pull and try the flow 🤓

With love and respect,
Arturo 👨🏻‍💻

Note: The sources below contain some minor errors corrected in this guide.
Sources: 1, 2

Great! Next, complete checkout for full access to ArturoFM.
Welcome back! You've successfully signed in.
You've successfully subscribed to ArturoFM.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info has been updated.
Your billing was not updated.