What is the current behavior?
I want to create a lambda function trigger PreSignUp and checks if there are other users already signed up using the same email.
here is my function:
'use strict';
const AWS = require('aws-sdk');
const cognitoIdp = new AWS.CognitoIdentityServiceProvider({apiVersion: '2016-04-18'});
exports.handler = function(event, context) {
console.log(JSON.stringify(event));
// check if email is already in use
if (event.request.userAttributes.hasOwnProperty('email')) {
const email = event.request.userAttributes.email;
const params = {
UserPoolId: event.userPoolId,
Filter: 'email = "' + email + '"',
};
cognitoIdp.listUsers(params).promise()
.then (results => {
console.log(JSON.stringify(results));
// if the usernames are the same, dont raise and error here so that
// cognito will raise the duplicate username error
if (results.Users.length > 0 && results.Users[0].Username !== event.userName) {
console.log('Duplicate email address in signup. ' + email);
context.done(Error('A user with the same email address exists'));
}
context.done(null, event);
})
.catch (error => {
console.error(error);
context.done(error);
});
}
};
I used to get such error
lambda is not authorized to perform: cognito-idp:ListUsers
Do you have any suggestion and how to configure the IAM-lambda role.
My current lambda role:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Here is my solution:
data "aws_iam_policy_document" "pre_signup_policy_doc" {
statement {
sid = ""
effect = "Allow"
actions = ["cognito-idp:ListUsers"]
resources = ["*"]
}
}
resource "aws_iam_role_policy" "iam_for_presignup_lambda_policy" {
role = "${aws_iam_role.iam_for_presignup_lambda.id}"
policy = "${data.aws_iam_policy_document.pre_signup_policy_doc.json}"
// policy = <<EOF
//{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "cognito-idp:ListUsers" ], "Resource": "*" } ] }
//EOF
}
@engharb can you share some context of how you’d use that data and resource snippet? I see there’s a <functionname>-cloufromation-template.json in my amplify project and maybe I can edit that?
(Also, does that duplicate check work for you, i.e., are you using the hosted UI and does it do something useful when you return that error?)
@mrcoles based on my knowledge this is separated issue. I mean there is no direct relation between configuring your aws-infrastructure than your-amplify-project settings. In order to be able to check i.e the existence of email or username in Cognito-User-Pool using Amplify-js or external API you have to create a policy enabling your Lambda functions to get access/permission to your Cognito-User-Pool (something like that).
And regarding <functionname>-cloufromation-template.json I have no idea what it is.
Honestly I'm not using Hosted UI directly. I used to create my own form and then validate the submitted data using Amplify-js API. And for social login I used to call
https://AUTH_DOMAIN/oauth2/authorize...
Not at all.
Thanks for the response. I was able to get it working in my AWS Amplify project. For anyone else who’s trying to figure it out…
In an AWS Amplify project they auto-create a bunch of stuff for you and when you create a lambda function amplify add function it ends up in a directory like this:
./amplify/backend/function/<function_name>/
And there’s a Cloudformation file in that directory at <function_name>-cloudformation-template.json. Under Resources.lambdaexecutionpolicy.Properties.PolicyDocument.Statement, I was able to add this additional statement:
{
"Effect": "Allow",
"Action": ["cognito-idp:ListUsers"],
"Resource": {
"Fn::Sub": [
"arn:aws:cognito-idp:${region}:${account}:*",
{
"region": {
"Ref": "AWS::Region"
},
"account": {
"Ref": "AWS::AccountId"
},
"lambda": {
"Ref": "LambdaFunction"
}
}
]
}
}
Using the hosted UI and returning an error with the newer callback syntax, exports.handler = function(event, context, callback) { … }, and if I do callback(Error('a user with the same email address exists')), then I get the error message:
PreSignUp failed with error a user with the same email address exists.

However, with Social Signin, instead of showing the me error in the UI, it redirects me back to my app to a URL like this:
https://localhost:1234/auth/signin?error_description=PreSignUp+failed+with+error+a+user+with+the+same+email+address+exists.+&error=invalid_request
and I have to handle that in my UI I suppose.
This isn’t ideal, but it’s something workable. Also, I’m flabbergasted that there’s no option to have Cognito pools make emails case-insensitive.
@mrcoles from today new User Pools can be created with case insensitivity for username input
More info [here] (https://aws.amazon.com/about-aws/whats-new/2020/02/amazon-cognito-user-pools-service-now-supports-case-insensitivity-for-user-aliases)
Most helpful comment
Thanks for the response. I was able to get it working in my AWS Amplify project. For anyone else who’s trying to figure it out…
List Users Permission
In an AWS Amplify project they auto-create a bunch of stuff for you and when you create a lambda function
amplify add functionit ends up in a directory like this:And there’s a Cloudformation file in that directory at
<function_name>-cloudformation-template.json. Under Resources.lambdaexecutionpolicy.Properties.PolicyDocument.Statement, I was able to add this additional statement:Error message in Hosted UI
Using the hosted UI and returning an error with the newer callback syntax,
exports.handler = function(event, context, callback) { … }, and if I docallback(Error('a user with the same email address exists')), then I get the error message:However, with Social Signin, instead of showing the me error in the UI, it redirects me back to my app to a URL like this:
and I have to handle that in my UI I suppose.
This isn’t ideal, but it’s something workable. Also, I’m flabbergasted that there’s no option to have Cognito pools make emails case-insensitive.