Cognito Custom Auth Flow: Create auth challenge lambda function is triggered multiple time

0

I'm trying to implement passwordless authentication in Cognito using lambda triggers. I've implemented the three lambda functions:

  • DefineAuthChallenge
  • CreateAuthChallenge
  • VerifyAuthChallenge

The issue is when I'm invoking initiateAuth API multiple events trigger the CreateAuthChallenge lambda. Hence, causing the user to receive more than one OTP for a given request. Below is the implementation of CreateAuthChallenge lambda.

` public class CreateAuthChallengeHandler implements RequestStreamHandler { private static final String SENDER_EMAIL = "user@gmail.com"; private static final String SUBJECT = "OTP"; public ObjectMapper objectMapper = new ObjectMapper();

@Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
    LambdaLogger logger = context.getLogger();
    JsonNode mainNode = objectMapper.readTree(input);
    logger.log("input: " + mainNode.toString());
    JsonNode session = mainNode.get("request").get("session");
    JsonNode userAttributes = mainNode.get("request").get("userAttributes");
    JsonNode responseNode = mainNode.get("response");
    int sessionLength = objectMapper.convertValue(session, ArrayList.class).size();
    String secretCode;
    if (sessionLength == 0) {
        logger.log("sessionLength: " + sessionLength);
        secretCode = getSecretCode();
        SesClient sesClient = SesClient.builder().region(Region.AP_SOUTH_1).build();
        try {
            logger.log("sending email ...");
            SendEmailRequest emailRequest = SendEmailRequest.builder()
                    .source(SENDER_EMAIL)
                    .destination(Destination.builder().toAddresses(userAttributes.get("email").asText()).build())
                    .message(Message.builder()
                            .subject(Content.builder().data(SUBJECT).build())
                            .body(Body.builder().text(Content.builder().data(secretCode).build()).build()).build())
                    .build();
            SendEmailResponse sendEmailResponse = sesClient.sendEmail(emailRequest);
            logger.log("sendEmailResult: " + sendEmailResponse.messageId());
        } catch (SesException e) {
            logger.log("Email sending failed. Error message: " + e.getMessage());
        } finally {
            sesClient.close();
        }
    } else {
        JsonNode previousChallenge = session.get(sessionLength - 1);
        secretCode = previousChallenge.get("challengeMetadata").asText();
        logger.log("secretCode: " + secretCode);
    }

    ((ObjectNode) responseNode).putPOJO("publicChallengeParameters", Map.of(
            "email", userAttributes.get("email").asText()));
    ((ObjectNode) responseNode).putPOJO("privateChallengeParameters", Map.of(
            "secretLoginCode", secretCode));
    ((ObjectNode) responseNode).put("challengeMetadata", secretCode);
    objectMapper.writeValue(output, mainNode);
    logger.log("output: " + output.toString());
}

} `

pom.xml

`

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>

<groupId>XXXXXXXX</groupId>
<artifactId>XXXXXXX</artifactId>
<version>4.7-SNAPSHOT</version>

<properties>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-lambda-java-core</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.17.0</version>
    </dependency>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>ses</artifactId>
        <version>2.25.40</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>9</source>
                <target>9</target>
            </configuration>
        </plugin>
    </plugins>
</build>
</project> `

Below are DefineAuthChallenge are logs: 2024-04-30T17:51:29.041+05:30 INIT_START Runtime Version: java:21.v15 Runtime Version ARN: arn:aws:lambda:ap-south-1::runtime:XXXXXX 2024-04-30T17:51:29.709+05:30 START RequestId: 81165b64-2ee5-4d40-83df-a3fc21faa856 Version: $LATEST 2024-04-30T17:51:30.032+05:30 input: {"version":"1","region":"ap-south-1","userPoolId":"XXXXXX","userName":"XXXXXX","callerContext":{"awsSdkVersion":"aws-sdk-java-1.12.641","clientId":"XXXXXX"},"triggerSource":"DefineAuthChallenge_Authentication","request":{"userAttributes":{"sub":"f113dd3a-1021-7084-2495-8c4eb4853463","email_verified":"True","custom:login-path":"XXXXXX","cognito:user_status":"CONFIRMED","name":"XXXXXX","email":"XXXXXX"},"session":[],"userNotFound":false},"response":{"challengeName":null,"issueTokens":null,"failAuthentication":null}} 2024-04-30T17:51:30.230+05:30 output: {"version":"1","region":"ap-south-1","userPoolId":"XXXXXX","userName":"XXXXXX","callerContext":{"awsSdkVersion":"aws-sdk-java-1.12.641","clientId":"XXXXXX"},"triggerSource":"DefineAuthChallenge_Authentication","request":{"userAttributes":{"sub":"f113dd3a-1021-7084-2495-8c4eb4853463","email_verified":"True","custom:login-path":"XXXXXX","cognito:user_status":"CONFIRMED","name":"XXXXXX","email":"XXXXXX"},"session":[],"userNotFound":false},"response":{"challengeName":"CUSTOM_CHALLENGE","issueTokens":false,"failAuthentication":false}} 2024-04-30T17:51:30.231+05:30 END RequestId: 81165b64-2ee5-4d40-83df-a3fc21faa856 2024-04-30T17:51:30.231+05:30 REPORT RequestId: 81165b64-2ee5-4d40-83df-a3fc21faa856 Duration: 521.66 ms Billed Duration: 522 ms Memory Size: 512 MB Max Memory Used: 111 MB Init Duration: 667.20 ms Below are the CreateAuthChallenge logs: 2024-04-30T17:51:35.423+05:30 INIT_START Runtime Version: java:21.v15 Runtime Version ARN: arn:aws:lambda:ap-south-1::runtime:XXXXXX 2024-04-30T17:51:36.085+05:30 START RequestId: a9efd773-08b6-4b4b-a2b3-d1fb7e3fb502 Version: $LATEST 2024-04-30T17:51:36.407+05:30 input: {"version":"1","region":"ap-south-1","userPoolId":"XXXX","userName":"user@gmail.com","callerContext":{"awsSdkVersion":"aws-sdk-java-1.12.641","clientId":"XXXXX"},"triggerSource":"CreateAuthChallenge_Authentication","request":{"userAttributes":{"sub":"XXXXXX","email_verified":"True","custom:login-path":"https://test.com","cognito:user_status":"CONFIRMED","name":"XXXXXXX","email":"XXXXXX"},"challengeName":"CUSTOM_CHALLENGE","session":[],"userNotFound":false},"response":{"publicChallengeParameters":null,"privateChallengeParameters":null,"challengeMetadata":null}} 2024-04-30T17:51:36.604+05:30 sessionLength: 0 2024-04-30T17:51:36.784+05:30 SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". 2024-04-30T17:51:36.784+05:30 SLF4J: Defaulting to no-operation (NOP) logger implementation 2024-04-30T17:51:36.784+05:30 SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 2024-04-30T17:51:40.811+05:30 sending email ... 2024-04-30T17:51:43.649+05:30 sendEmailResult: 0109018f2ef42538-54f24435-4449-46c6-afb7-8750fbf5de56-000000 2024-04-30T17:51:43.710+05:30 output: {"version":"1","region":"ap-south-1","userPoolId":"XXXXXX","userName":"XXXXXX","callerContext":{"awsSdkVersion":"aws-sdk-java-1.12.641","clientId":"XXXXXX"},"triggerSource":"CreateAuthChallenge_Authentication","request":{"userAttributes":{"sub":"XXXXXX","email_verified":"True","custom:login-path":"https://XXXXXX","cognito:user_status":"CONFIRMED","name":"XXXXXX","email":"XXXXXX"},"challengeName":"CUSTOM_CHALLENGE","session":[],"userNotFound":false},"response":{"publicChallengeParameters":{"email":"XXXXXX"},"privateChallengeParameters":{"secretLoginCode":"6605"},"challengeMetadata":"6605"}} 2024-04-30T17:51:43.724+05:30 END RequestId: a9efd773-08b6-4b4b-a2b3-d1fb7e3fb502 2024-04-30T17:51:43.724+05:30 REPORT RequestId: a9efd773-08b6-4b4b-a2b3-d1fb7e3fb502 Duration: 7639.15 ms Billed Duration: 7640 ms Memory Size: 512 MB Max Memory Used: 169 MB Init Duration: 661.01 ms 2024-04-30T17:52:25.756+05:30 START RequestId: d39e6945-45a2-4f81-a0b3-c860afdb47d4 Version: $LATEST 2024-04-30T17:52:25.757+05:30 input: {"version":"1","region":"ap-south-1","userPoolId":"XXXXXX","userName":"XXXXXX","callerContext":{"awsSdkVersion":"aws-sdk-java-1.12.641","clientId":"XXXXXX"},"triggerSource":"CreateAuthChallenge_Authentication","request":{"userAttributes":{"sub":"XXXXXX","email_verified":"True","custom:login-path":"https://XXXXXX","cognito:user_status":"CONFIRMED","name":"XXXXXX","email":"XXXXXX"},"challengeName":"CUSTOM_CHALLENGE","session":[],"userNotFound":false},"response":{"publicChallengeParameters":null,"privateChallengeParameters":null,"challengeMetadata":null}} 2024-04-30T17:52:25.757+05:30 sessionLength: 0 2024-04-30T17:52:25.766+05:30 sending email ... 2024-04-30T17:52:25.958+05:30 sendEmailResult: 0109018f2ef4cb42-08000c0f-1d0f-411c-bc90-473fa1542e0d-000000 2024-04-30T17:52:25.965+05:30 output: {"version":"1","region":"ap-south-1","userPoolId":"XXXXXX","userName":"XXXXXX","callerContext":{"awsSdkVersion":"aws-sdk-java-1.12.641","clientId":"XXXXXX"},"triggerSource":"CreateAuthChallenge_Authentication","request":{"userAttributes":{"sub":"XXXXXX","email_verified":"True","custom:login-path":"https://XXXXXX","cognito:user_status":"CONFIRMED","name":"XXXXXX","email":"XXXXXX"},"challengeName":"CUSTOM_CHALLENGE","session":[],"userNotFound":false},"response":{"publicChallengeParameters":{"email":"XXXXXX"},"privateChallengeParameters":{"secretLoginCode":"5757"},"challengeMetadata":"5757"}} 2024-04-30T17:52:25.966+05:30 END RequestId: d39e6945-45a2-4f81-a0b3-c860afdb47d4 2024-04-30T17:52:25.966+05:30 REPORT RequestId: d39e6945-45a2-4f81-a0b3-c860afdb47d4 Duration: 210.20 ms Billed Duration: 211 ms Memory Size: 512 MB Max Memory Used: 171 MB

3 Answers
1

In your first create Challenge Lambda log:

REPORT RequestId: a9efd773-08b6-4b4b-a2b3-d1fb7e3fb502 Duration: 7639.15 ms Billed Duration: 7640 ms

In the documentation of Cognito lambda triggers https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#important-lambda-considerations

Except for Custom sender Lambda triggers, Amazon Cognito invokes Lambda functions synchronously. When Amazon Cognito calls your Lambda function, it must respond within 5 seconds

As the 7.6 seconds lambda execution is longer than 5s. Cognito side takes it as time out and make an auto-retry.

Java runtime lambda has the most long cold-start time cost. You may search for aws lambda cold start to understand more. There are also many articles talked about how to mitigate that.

profile pictureAWS
Yungang
answered 5 months ago
  • If you see the logs, the 'Init Duration' is not much but what is taking time is the code execution.

    REPORT RequestId: a9efd773-08b6-4b4b-a2b3-d1fb7e3fb502 Duration: 7639.15 ms Billed Duration: 7640 ms Memory Size: 512 MB Max Memory Used: 169 MB Init Duration: 661.01 ms

    My Code for sending email is taking around 9 seconds. 6 seconds jus to initialize SesClient and another 3 seconds to send email:

    try(SesClient sesClient = SesClient.builder().region(Region.AP_SOUTH_1).build()) { logger.log("sending email ..."); SendEmailRequest emailRequest = SendEmailRequest.builder() .source(SENDER_EMAIL) .destination(Destination.builder().toAddresses(userAttributes.get("email").asText()).build()) .message(Message.builder() .subject(Content.builder().data(SUBJECT).build()) .body(Body.builder().text(Content.builder().data(secretCode).build()).build()).build()) .build(); SendEmailResponse sendEmailResponse = sesClient.sendEmail(emailRequest); logger.log("sendEmailResult: " + sendEmailResponse.messageId()); } catch (SesException e) { logger.log("Email sending failed. Error message: " + e.getMessage()); }

    Is there any way to optimize this piece of code or should I move the email part to another lambda which runs in async.

0

Not sure why the second execution is only 210ms

REPORT RequestId: d39e6945-45a2-4f81-a0b3-c860afdb47d4 Duration: 210.20 ms

Is there any way to optimize this piece of code

I am using python lambda with 'smtplib' to send email for createAuthChallenge, never see an issue. I am not using SES, but a SMTP server to deliver email.

should I move the email part to another lambda which runs in async.

Sounds a possible option.

profile pictureAWS
Yungang
answered 5 months ago
0

I got it working to run under 5 seconds by increasing the memory to 2048 MB (which also allocates CPU power linearly) Below are the logs for reference:

`

2024-05-03T14:05:28.408+05:30	INIT_START Runtime Version: java:21.v15 Runtime Version ARN: arn:aws:lambda:ap-south-1::runtime:367cb4c78c9b9b4d4eb04656c9938e85fbed3f853a08f5e0a5f21a46326d3991
2024-05-03T14:05:29.072+05:30	START RequestId: 4343bf41-007c-483b-8f12-3e65a8605a57 Version: $LATEST
2024-05-03T14:05:29.140+05:30	input: {"version":"1","region":"ap-south-1","userPoolId":"XXXXXX","userName":"XXXXXX","callerContext":{"awsSdkVersion":"aws-sdk-java-1.12.641","clientId":"XXXXXX"},"triggerSource":"CreateAuthChallenge_Authentication","request":{"userAttributes":{"sub":"f113dd3a-1021-7084-2495-8c4eb4853463","email_verified":"True","custom:login-path":"XXXXXX","cognito:user_status":"CONFIRMED","name":"XXXXXX","email":"XXXXXX"},"challengeName":"CUSTOM_CHALLENGE","session":[],"userNotFound":false},"response":{"publicChallengeParameters":null,"privateChallengeParameters":null,"challengeMetadata":null}}
2024-05-03T14:05:29.184+05:30	sessionLength: 0
2024-05-03T14:05:29.184+05:30	secretCode: 9184
2024-05-03T14:05:30.696+05:30	sending email ...
2024-05-03T14:05:31.428+05:30	sendEmailResult: 0109018f3d982161-5ca0d668-16e4-4741-a24a-9b82204bef24-000000
2024-05-03T14:05:31.442+05:30	output: {"version":"1","region":"ap-south-1","userPoolId":"XXXXXX","userName":"XXXXXX","callerContext":{"awsSdkVersion":"aws-sdk-java-1.12.641","clientId":"XXXXXX"},"triggerSource":"CreateAuthChallenge_Authentication","request":{"userAttributes":{"sub":"f113dd3a-1021-7084-2495-8c4eb4853463","email_verified":"True","custom:login-path":"XXXXXX","cognito:user_status":"CONFIRMED","name":"XXXXXX","email":"XXXXXX"},"challengeName":"CUSTOM_CHALLENGE","session":[],"userNotFound":false},"response":{"publicChallengeParameters":{"email":"XXXXXX"},"privateChallengeParameters":{"secretLoginCode":"9184"},"challengeMetadata":"9184"}}
2024-05-03T14:05:31.445+05:30	END RequestId: 4343bf41-007c-483b-8f12-3e65a8605a57
2024-05-03T14:05:31.445+05:30	REPORT RequestId: 4343bf41-007c-483b-8f12-3e65a8605a57 Duration: 2372.51 ms Billed Duration: 2373 ms Memory Size: 2048 MB Max Memory Used: 199 MB Init Duration: 662.88 ms

`

NOTE: This however increases the price per 1ms which is $0.0000000333 for 2048 MB.

Shubham
answered 5 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions