Leveraging Serverless (SAM) with Cognito Authentication

By Morten Jensen

| 3 minutes read


Using Serverless combined with Cognito can be a great way to eliminate the real estate as well as development and operational footprint when it comes to authentication and authorisation stacks.

Furthermore, Cognito is also likely to further enhance overall security posture when compared to in particular homebrewn alternatives.

We have put together a full demonstration Cognito application stack based on Serverless (SAM). This includes code, infrastructure as code and a Codepipeline. All ready to go (with some prerequisites).


The demonstration is a somewhat simplified implementation and demonstrates the following capabilities:

  • Numerous AWS CLI Cognito authentication examples (did you know that you can act as a Cognito user with the AWS CLI?)
  • AWS Codepipeline to perform source, build and deployment to development (single-stage pipeline) or test and production (multi-stage pipeline)
  • AWS CodeBuild for build of application stack and code
  • Cognito User Pool for user authentication
  • Cognito custom domain with hosted UI where web browser users can sign-up, confirm account and sign-in
  • Cognito Identity Pool to demonstrate both unauthenticated and authenticated access and exchange of Cognito token for temporary AWS credentials that can be used to interact with AWS services (in this case AWS PinPoint)
  • Cognito Resource Server to demonstrate how to obtain OAuth2 client (service-to-service) credentials
  • Cognito User Group to demonstrate how to add users to a group
  • AWS Lambdas to demonstrate Cognito integration: User Pre-Signup trigger (validates email address and email domain from a list of disposable email domains), User Sign-in (used both Pre and Post) trigger, Post-Signup trigger
  • API Gateway to demonstrate user and guest access
  • AWS Lambda underpinning the API Gateway to demonstrate guest and user access via ID token
  • AWS SNS topic where that user events are posted to (creation and sign-in)
  • AWS CloudWatch Log Groups (with automatic encryption applied via custom resource)
  • AWS CloudWatch Dashboard for runtime metrics surrounding the AWS Lambdas
  • Route 53 records for both Cognito hosted UI and API Gateway (this does require AWS-hosted domains)


Cognito, as with all other technologies, has a number of limitations to consider.

  • Currently there are no CloudWatch metrics for Cognito. Advanced offers per-user metrics but it is a costly option
  • There’s only very limited Cognito logging out of the box (user migration)
  • Cognito Cloudformation coverage is not complete although very recently it did get better. For instance AWS::Cognito::UserPoolDomain does not return the required alias target (Cloudfront distribution) in order to create a Route53 AA record
  • Cognito Lambda trigger execution time has a maximum of 5 seconds. The trigger is retried 3 times at which point the user request (sign-up, sign-in, user migration etc.) is failed. This limitation does make Lambda invocation very tricky if the Lambda is attached to a VPC due to cold-start

To workaround some of the cons consider:

  • To get Cognito usage metrics, introduce pre/post sign-in and sign-up Lambda triggers that log events to CloudWatch Logs.
  • We included a UserPoolDomain custom resource that supports returning the alias target (Cloudfront distribution) in order to create a Route53 AA record
  • Where possible, avoid attaching triggers to a VPC. Alternatively, a mitigation would be to trigger each Lambda trigger regularly to keep Lambda instances warm for as long as possible


Authentication and authorisation stacks don’t have to be daunting. We have provided a fairly comprehensive example of a Serverless Cognito stack.

Much more is possible. A couple of examples:

  • Password-less authentication with Cognito using the authentication challenge Lambda triggers
  • Complete customisation of messages with proper html formatted emails for password-less authentication, sign-up and even a welcome email
  • Seemless user migration from legacy authentication stacks with the help of some Cognito Lambda trigger plumbing

Feel free to raise any bugs/issues on GitHub and we will try to address them. Even better, feel free to issue pull requests (that also includes documentation).