Serverless + Step Functions — Copy users from Cognito to DynamoDB

Yi Ai
The Cloud Builders Guild
3 min readSep 17, 2018

It is simple and convenient to use a Lambda function for implementing task states. I will show you the process of using Step functions to send custom notification after new user signed up in Cogntio User Pool and after, sync new created user to DynamoDB.

Install Serverless Framework

Before getting started, Install the Serverless Framework.

Open up a terminal and type npm install -g serverless to install Serverless.

Create a new service

Create a new service using the Node.js template, specifying a unique name and an optional path for my service.

$ serverless create --template aws-nodejs --path cognitoSync
$ cd cognitoSync

Install Serverless Plugin

Then can run the following command project root directory to install Serverless Step Functions Plugin, the plugin will be added automatically in plugins array in my serverless.yml file.

$ serverless plugin install --name serverless-step-functions

You can also install serverless-pseudo-parameters Plugin, with this plugin you can use AWS pseudo parameters like #{AWS::AccountId}, #{AWS::Region}, It makes it easy to set up in Resource section in serverless.yml .

Getting Started

What I want to achieve is after new user is confirmed, lambda function sends custom email to this user and a step function copy newly conformed user to DynamoDb User Table.

Define AWS state language

The following is example state machine definition, which is composed of a single lambda function to copy user from Cognito to User table.

stepFunctions:
stateMachines:
cognitoSyncDynamodbFlow:
name: cognitoSyncDynamodbFlow-${opt:stage}
definition:
Comment: "Sync User from Cognito to Dynamodb"
StartAt: CognitoSyncDynamodb
States:
CognitoSyncDynamodb:
Type: Task
Resource: arn:aws:lambda:${opt:region}:#{AWS::AccountId}:function:${self:service}-${opt:stage}-syncCognitoToDynamodb
End: true
plugins:
- serverless-step-functions
- serverless-pseudo-parameters

syncCognitoToDynamodb is Lambda function to copy user to DynamoDB User tabe

module.exports.syncCognitoToDynamodb = (event, context, callback) => {
const {
request: {
userAttributes: { sub: id, name = "", email = "", phone_number = "" }
}
} = event;
const parmItem = {
id,
name,
email,
phone_number
};
const params = {
TableName: process.env.userTable,
Item: parmItem
};
documentClient
.put(params)
.promise()
.then(r => {
return callback(null, event);
})
.catch(err => {
return callback(null, err);
});
};

Use triggered Lambda events

Here’s example serverless.yml config triggered state machine by Post Confirmation Lambda Trigger.

functions:
postUserConfirm :
handler: handler.postUserConfirm
environment:
statemachine_arn: ${self:resources.Outputs.CognitoSyncDynamodbFlow.Value}
clientId: ${self:custom.eHealthClient.${opt:stage}}
syncCognitoToDynamodb:
handler: handler.syncCognitoToDynamodb
environment:
userTable: ${self:custom.userTable.${opt:stage}}
resources:
Outputs:
CognitoSyncDynamodbFlow:
Description: The ARN of the state machine
Value:
Ref: CognitoSyncDynamodbFlowDash${opt:stage}

Then Using the AWS SDK, Lambda function send custom user notification and trigger step functions:

exports.postUserConfirm = (event, context, callback) => {
if (event.request.userAttributes.email) {
sendEmail(
event.request.userAttributes.email,
"Congratulations " + event.userName + ", you have been confirmed: ",
function(status) {}
);
}
const stateMachineArn = process.env.statemachine_arn;
const params = {
input: JSON.stringify(event),
stateMachineArn
};
return stepfunctions
.startExecution(params)
.promise()
.then(() => {
callback(null, event);
})
.catch(error => {
callback(error.message);
});
};

As an existing issue of Serverless Framework #4207, there is no way to reference existing Cognito User Pool resource in configuration, so you have to manually assign the deployed Lambda function to the “Post confirmation” trigger, before this step, deploy the service to AWS otherwise you won’t find lambda functions in the Cognito User Pool trigger lambda list.

serverless deploy --stage production --region yourRegion

Then you can go to AWS console, Cognito User Pool to setup the trigger lambda function

Cognito User Pool General Settings --> Triggers --> Post Confirmation

All done!!!

Please refer to the GitHub project for the full source code:

--

--

Yi Ai
The Cloud Builders Guild

AWS Community Builder | AWS AZURE GCP Certified Engineer | A Cloud Technology Enthusiast | AWS Certified Security/Machine Learning/Database Analytics Specialty