Skip to content

How can I add custom logic for failed sign in attempt in cognito hosted UI?

1

When user sign in through hosted UI and it failed * (meaning incorrect email or password)* for 10 times, I want to block the user.

I noticed there are lambda triggers but I can't determine Pre authentication Lambda trigger or Post authentication Lambda trigger since I can't find documentation for failed attempts.

1 Answer
1
Accepted Answer

Greeting

Hi Josue,

Thanks for reaching out to the AWS re:Post community! Your question about adding custom logic for failed sign-in attempts in the Cognito hosted UI is a great one, as it dives into improving security through automation. Let’s break this down and work towards a practical solution together. 😊


Clarifying the Issue

From your description, you're looking to implement custom logic to block a user after multiple failed login attempts (e.g., 10 incorrect email/password attempts) in the Cognito hosted UI. You've explored Lambda triggers but haven't been able to determine whether a Pre-Authentication or Post-Authentication trigger can handle this scenario because of documentation limitations around failed attempts. This sounds like a security-focused enhancement, and you're right that Cognito doesn't natively track failed attempts in the hosted UI. We'll address this gap with an actionable workaround!


Key Terms

Here are some key concepts to clarify:

  • Cognito Hosted UI: The out-of-the-box sign-in/sign-up interface provided by Amazon Cognito.
  • Lambda Triggers: Customizable AWS Lambda functions that can augment the Cognito authentication workflow (e.g., Pre-Authentication, Post-Authentication).
  • Pre-Authentication Trigger: A trigger invoked before a sign-in attempt is validated by Cognito.
  • DynamoDB: A fully managed NoSQL database service used to store and retrieve failed login data.
  • CloudWatch Logs: A logging service where failed login attempts can be tracked for further analysis or integration.
  • AWS WAF: A web application firewall that can block or rate-limit suspicious login attempts based on pre-configured rules.
  • IAM Permissions: Policies that govern access rights to AWS services, ensuring secure execution of your Lambda function.

The Solution (Our Recipe)

Steps at a Glance:

  1. Enable the Pre-Authentication Lambda trigger in your Cognito User Pool.
  2. Set up a DynamoDB table to log failed login attempts.
  3. Implement a Lambda function to track failed attempts and block users exceeding the threshold.
  4. Test the Lambda function to ensure it works as expected.
  5. Add CloudWatch logs for debugging and monitoring (optional).
  6. Configure AWS WAF to block repeated login attempts.
  7. Configure IAM permissions for secure access to DynamoDB and CloudWatch.
  8. Plan for DynamoDB scaling and cost optimization.

Step-by-Step Guide:

  1. Enable the Pre-Authentication Lambda Trigger:
    • Navigate to your Cognito User Pool in the AWS Management Console.
    • Under Triggers, attach a Lambda function to the Pre-Authentication trigger.

  1. Set Up DynamoDB to Log Failed Login Attempts:
    • Create a DynamoDB table named FailedLoginAttempts.
    • Define two key attributes: username (partition key) and failedAttempts.
    • Add an optional attribute lastFailedAttempt to track timestamps.

  1. Implement the Lambda Function: Use the following example to handle failed login attempts:

    import boto3
    from datetime import datetime, timedelta
    
    dynamodb = boto3.client('dynamodb')
    
    def lambda_handler(event, context):
        username = event['userName']
        table_name = 'FailedLoginAttempts'
    
        try:
            # Fetch user record
            response = dynamodb.get_item(
                TableName=table_name,
                Key={'username': {'S': username}}
            )
            user = response.get('Item', {})
    
            # Initialize or update failed attempts
            failed_attempts = int(user['failedAttempts']['N']) if user else 0
            last_attempt = datetime.strptime(user['lastFailedAttempt']['S'], '%Y-%m-%dT%H:%M:%S') if user else None
    
            # Reset counter if 24 hours have passed
            if last_attempt and datetime.now() - last_attempt > timedelta(hours=24):
                failed_attempts = 0
    
            # Increment counter or block user
            failed_attempts += 1
            if failed_attempts > 10:
                raise Exception('User is blocked due to repeated failed login attempts.')
    
            # Update DynamoDB
            dynamodb.put_item(
                TableName=table_name,
                Item={
                    'username': {'S': username},
                    'failedAttempts': {'N': str(failed_attempts)},
                    'lastFailedAttempt': {'S': datetime.now().isoformat()}
                }
            )
    
        except Exception as e:
            # Log and re-raise errors for visibility
            print(f"Error processing login for user {username}: {e}")
            raise
    
        return event
    • This function checks the number of failed attempts and blocks the user if the threshold is exceeded.
    • It resets the counter after 24 hours, preventing permanent lockouts.

  1. Test the Lambda Function:
    • Use the AWS Lambda console's Test feature to simulate failed login attempts.
    • Confirm that failed attempts are recorded in DynamoDB and users are blocked after exceeding the limit.

  1. Integrate CloudWatch Logs (Optional):

    • Add logging to your Lambda function for easier debugging:
    import logging
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    
    logger.info(f"Failed attempts for user {username}: {failed_attempts}")

  1. Configure AWS WAF for Enhanced Security:
    • AWS WAF can protect your Cognito hosted UI by blocking repeated login attempts from the same IP address. Here’s a quick setup example:
      1. Open the AWS WAF console and create a Web ACL.
      2. Add a Rate-Based Rule:
        • Set the rate limit to 10 requests per 5 minutes.
        • Add a condition to target the hosted UI endpoint.
      3. Attach the Web ACL to your API Gateway or CloudFront distribution serving the Cognito hosted UI.
    • For detailed automation, use the AWS CLI or CloudFormation to create rules programmatically.

  1. Configure IAM Permissions:
    • Ensure the Lambda function has appropriate IAM permissions to interact with DynamoDB and CloudWatch Logs securely.
    • Attach the following managed policies to your Lambda execution role:
      • AmazonDynamoDBFullAccess or a scoped-down custom policy for DynamoDB.
      • CloudWatchLogsFullAccess or scoped permissions for logging.

  1. Plan for DynamoDB Scaling and Cost Optimization:
    • Use Auto Scaling: Configure DynamoDB to handle variable traffic patterns by enabling auto-scaling policies.
    • Monitor usage: Set up CloudWatch alarms for read/write throughput and data storage costs.
    • Optimize indexes: Regularly review and optimize Global Secondary Indexes (GSIs) to avoid unnecessary costs.

Closing Thoughts

With this solution, you can effectively monitor and block users after repeated failed login attempts, enhancing the security of your Cognito hosted UI. Below are some helpful documentation links to guide you further:


Farewell

I hope this solution helps you implement the custom logic you're looking for, Josue! Let me know if you have any questions or need further clarification. Good luck, and happy building! 🚀✨


Cheers,

Aaron 😊

answered a year ago
EXPERT
reviewed a year ago
  • Hello @Aaron Rose, I really appreciate your detailed response. Thank you very much. I'll let you know if I have further questions.

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.