AWS Lambda error on Cognito User Pool trigger - amazon-web-services

I'm trying to insert a record into DynamoDB invoking "Pre sign-up" trigger of Cognito User Pool.
Lambda function is pretty simple for testing purposes but there is always an error in client application on AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool.signUp call
Use case 1
Lambda body:
console.log('Received event:', JSON.stringify(event, null, 2));
Result:
InvalidLambdaResponseException: Invalid lambda function output : Invalid JSON
Use case 2
Lambda body:
callback("null", "success");
Result:
InvalidLambdaResponseException: Invalid lambda function output : Invalid JSON
Use case 3
Lambda body:
new AWS.DynamoDB.DocumentClient().put(params, callback);
Result:
InvalidLambdaResponseException: Invalid cognito sign in version. Version should be 1
So, any ideas what might be wrong?
Could the latest error might be related to the beta status of Cognito User Pool?
P.S. I will provide more details if needed. Thanks in advance.

You are doing this in node.js and the error indicates you are not returning the service expected event source.
You should call context.done() when your lambda function finishes execution. Also, in any of the trigger sources which Cognito User Pool service generates, you can only edit the "response" part of the the source. For example, "autoConfirmUser" flag in PreSignUp trigger source.
Look at the examples in our developer guide for more details on this.

#user3479125
To do the same in python just return an event as is, or with modifications in datasets.
This code is supposed to run between the mobile device and cognito, so it can modify the event and it should return it back, so Sync event will finish successfully.
Some more explanations here

Try returning callback("null", event);
This should solve your problem.

Related

Can a lambda return a response and wait for a new body without closing the session?

I am running a puppeteer function in AWS Lambda and I have a scenario that the user makes a POST request to the lambda with his username and email. The function is going to check if they are valid in a website and return the JSON to the user with the answer. Is it possible to use the same lambda session to receive another input/body from the user?
The reason I need it to be the same session is because each time an user and email is sent to the lambda, the puppeteer website is going to generate unique ID's that need to be used AFTER the user sends his data in that exact moment because it is logged into the website with an unique session.
I'm currently running this function in a NodeJS and it is fine because the session isnt going to be closed but the session is closed once the lambda returns the first response.
Like people mentioned above, Lambda function is stateless resource and you can ultimately use dynamoDB to store any values such session ID or so.
Additionally, if the Lambda function should wait for response or any updated values by querying DynamoDB, then you can implement AWS Step Function or Airflow which provides the "wait" state.
See what States you can leverage in the AWS Docs.

Can Amazon Connect retrieve the error message from a lambda function?

Is it possible to capture a thrown error message from a lambda function in Amazon Connect?
Example lambda throwing an error:
exports.handler = async (event) => {
throw new Error('some error message')
};
I would like to use the error message in a voice prompt, without catching the error.
When a synchronous invocation returns an error, Amazon Connect retries up to 3 times, for a maximum of 8 seconds. At that point, the flow will progress down the Error branch.
An Error branch, is this what you want? see document
Yes, just return it in the response and then access via contact attribute.

Cognito passwordless solution sends code multiple times

I have successfully implemented these instructions from AWS (https://aws.amazon.com/de/blogs/mobile/implementing-passwordless-email-authentication-with-amazon-cognito/), but as soon as I execute the signIn function via aws-amplify, it often takes up to 7 seconds and I receive 3 emails with different codes.
The reason for this is that the event createAuthChallenge executes the respective lambda function 3 times, which generates and sends the respective code. This only happens if I do not login/register for a certain time (~10 minutes). I thought that this might be because the function is cold and tried to keep it warm by setting "Provisioned Concurrency" in the lambda functions
CreateAuthChallenge
VerifyAuthChallenge
DefineAuthChallenge
PreSignup
PostAuthentication
to 1 and additionally(!) tried to warm up the functions by executing them every 5 minutes via cloudwatch.
I don't know what else I should do.
Thx!
We had followed a different post to setup our custom auth flow, but had the same issue with 3 codes being sent out.
In that post it has the CreateAuthChallenge lambda start with
exports.handler = async (event) => {
const crypto = require('crypto')
const aws = require('aws-sdk')
...
}
We have been able to stop sending 3 verification codes by moving those requires outside of the handler method.
const crypto = require('crypto')
const aws = require('aws-sdk')
exports.handler = async (event) => {
...
}
My guess is that trying to read the entire aws-sdk inside of the function was the cause of the slowness and because this lambda took longer than the cognito system allows for, it ended up getting called multiple times and eventually did complete, thus causing the extra verification codes.
I did not see the same issue from the link you posted, but it would worth reviewing the specific code you have and check if its trying to bring in a package that needs to be handled differently.
You get 5 seconds for the lambda to complete, otherwise it retries. Cold starts and the blocking call to send the email via SES is what is eating all of those 5 seconds. You can make the call to SES asynchronous by writing the code, email address, timestamp and other necessary details to the log instead with some fixed prefix like SEND_EMAIL. Since this is sensitive data, you should encode the data into some format like json, encrypt it and base64 encode it before writing it to the log. Then you can attach a Cloudwatch subscription filter to the lambda log to route the log lines with SEND_EMAIL to a lambda to decrypt and decode the details and send the actual email via SES. This allows you to take longer than 5 seconds to send the email and workaround the timeouts.

Lex: The server encountered an error processing lambda

I'm developing a chatbot on AWS Lex and I want to use Lambda function to branch my intent.
In order to do so, I created a Lambda as follows:
exports.handler = async (event) => {
console.log(event); //capture Lex params
/*
let { name, slots } = event.currentIntent
if(slots.MeetingType.toLowerCase() === 'on-line') {
return {
dialogAction: {
type: "ElicitSlot",
intentName: name,
slotToElicit: "InvitationLink",
slots
}
}
}
return {
dialogAction: {
type: "Delegate",
slots
}
}
*/
};
But as you can see, even when the function does nothing but log Lex output, I'm getting this error message in Lex:
An error has occurred: The server encountered an error processing the
Lambda response
Any help would be appreciated.
Because you are trying to build a Lex chatbot using JavaScript, please refer to this use case in the AWS SDK for JavaScript DEV Guide. It will walk you through this use case:
Building an Amazon Lex chatbot
Once you get this working, you can port the logic to a Lambda function.
Amazon Lex is giving you this error message because the Lambda function has failed during execution.
Enable CloudWatch logging for your Lambda function and check the logs after Lex has called it. The logs should provide you with more specific details about what's caused the code to break/fail. From there you should have a better idea of how to resolve the issue.
Feel free to post the output from the logs if you need more assistance with debugging the issue.

AWS IoT - Failed to invoke lambda function

I'm trying to get my IoT device to fire off a Lambda function. Been trying for a few hours to no avail.
My lambda function is simple:
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify(event.message),
};
return response;
};
I've setup my IoT rule to trigger the lambda function with SELECT * FROM 'iot/trigger-lambda'. When I publish a message to the iot/trigger-lambda topic from AWS IoT's Test functionality, the lambda function triggers successfully. But, when I publish my message from my device, I get the following error:
{
"ruleName": "ruleTriggerLambda",
"topic": "iot/trigger-lambda",
"cloudwatchTraceId": "xxx-yyy-zzz",
"clientId": "ABC123",
"base64OriginalPayload": "eydvcGVyYGTpb24nOiAncHV0T2JqZWN0JywgJ2J1Y2tldCc6ICdyZWR3YXZlLWFwcC1kZXYnLCAna2V5JzogJ3JlYWNoYmFjay56aXAnLQWncmVwbHlUbyc6ICdpb3QvdGhyGHT0aWQtMDAwMS9wcmUtc2lnbmVkLBNzLXVybC1yBBNwb25zZXMnfSBbMV0=",
"failures": [
{
"failedAction": "LambdaAction",
"failedResource": "arn:aws:lambda:us-east-1:xxx:function:lambdaTriggerLambda",
"errorMessage": "Failed to invoke lambda function. Received Server error from Lambda. The error code is 400"
}
]
}
When I added the lambda function to my rule, AWS indicated it would create the correction permissions. I've also tried updating the permissions of the lambda function.
Any suggestions on how to fix this? Any help/information is much appreciated.
Edit: after 4 hours or ripping my hair out
It turned out to be the format of the data that I was sending as a payload from my IoT device. Let me explain, if someone can tell me why this is, I'd love to know.
I was using my mac as my device and I implemented this code from the AWS IoT Python SDK. My message looked like this:
message = {"message": "test message"}
It seems like pretty straight forward json.
The code that is publishing the message looks like this:
mqtt_connection.publish(
topic=args.topic,
payload=args.message,
qos=mqtt.QoS.AT_LEAST_ONCE)
The payload being received at AWS IoT Core looked like this:
{'message': 'test message'} [1]
And was accompanied by an error message like so: We cannot display the message as JSON, and are instead displaying it as UTF-8 String.
I guess I'm a little dense for not connecting the dots but it turns out I had to do the following to my code:
mqtt_connection.publish(
topic=args.topic,
payload=json.dumps(args.message).replace("\"", '').replace("[1]", '').replace("'", '"'),
qos=mqtt.QoS.AT_LEAST_ONCE)
Hopefully this explanation will help someone in the future.