AWS SAM Lambda Sample app with Cognito

Thusitha Jayasundara
4 min readOct 31, 2023

--

Photo by Mehmet Ali Peker on Unsplash

Introduction

This post contains source code and instructions to create a simple AWS Lambda application as a backend and API Gateway to invoke the Lambda. Also, instructions to configure AWS Cognito to secure the authentication between the API gateway and the client application. Furthermore, we will use AWS CodePipeline to configure the CI/CD pipeline. So this will be a fantastic journey.

Technologies

  • Node.js
  • AWS Lambda
  • AWS SAM
  • AWS Cognito
  • AWS API Gateway
  • AWS CodeCommit
  • AWS CodeBuild
  • AWS CodePipeline

Prerequisites

  1. An AWS Account
  2. Text Editor (I am using VS Code because it is incredible.)

Let us get started

These are the steps that I am going to cover. So, buckle up, folks!!!

  1. Create the repository in AWS
  2. Configure SAM template(template.yaml) file
  3. Configure Cognito resources
  4. Configure API gateway
  5. Configure the Lambda function
  6. Configure buildspec.yml file
  7. Configure the CI/CD pipeline (AWS CodePipeline)

Create the repository in AWS.

We can use the AWS SAM template to create the project. Please visit AWS SAM official GitHub page for more details. Otherwise, you can fork this repo and test the functionality.

Configure SAM template(template.yaml) file

For this example, We are going to use these parameters. You can pass these values from the AWS CodePipeline as parameters.

  • IAMExecutionRole - AWS user role to execute the Lambda.
  • CognitoUserPoolName - AWS Cognito userpool name.
  • CognitoUserPoolClientName - The name of the AWS Cognito User Pool client.
  • CognitoUserPoolDomain - The domain prefix that we are going to use to get the token.
  • CognitoUserPoolResourceServerName - Resource Server name for AWS Cognito User Pool Resource Server.
  • CognitoUserPoolResourceServerIdentifier - Unique identifier for AWS Cognito User Pool Resource Server.

Configure template.yaml file with the below configs if you need to have a dynamic template.

Parameters:
IAMExecutionRole:
Description: IAM role ARN of Lambda execution role.
Type: String
CognitoUserPoolName:
Description: Name for your Cognito user pool
Type: String
CognitoUserPoolClientName:
Description: Name for your Cognito user pool client
Type: String
CognitoUserPoolDomain:
Description: Domain name for your Cognito user pool
Type: String
CognitoUserPoolResourceServerName:
Description: Name for your Cognito user pool Cognito user pool resource server
Type: String
CognitoUserPoolResourceServerIdentifier:
Description: Identifier for your Cognito user pool resource server
Type: String

Configure Cognito User Pool.

Since we plan to use AWS Cognito to authenticate the client app with the Lambda functions, we need to configure AWS Cognito User Pool.

MyCognitoUserPool: # You can choose your own name.
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: !Ref CognitoUserPoolName # Refferencing User Pool Name parameter.
Policies:
PasswordPolicy:
MinimumLength: 8
UsernameAttributes:
- email
Schema:
- AttributeDataType: String
Name: email
Required: false

Configure Cognito User Client

To get the token first, we need to have a client for our User Pool. You can use the below configurations to create the User Pool Client.

MyCognitoUserPoolClient: # You can choose your own name.
Type: AWS::Cognito::UserPoolClient
Properties:
UserPoolId: !Ref MyCognitoUserPool # Refferencing Cognito User Pool created previously.
ClientName: !Ref CognitoUserPoolClientName # Refferencing User Pool Client Name parameter.
GenerateSecret: true
AllowedOAuthFlows:
- client_credentials
AllowedOAuthFlowsUserPoolClient: true
AllowedOAuthScopes:
- !Join ["/", [!Ref CognitoUserPoolClientName, "create"]] # You can configure Authentication scopes also.
- !Join ["/", [!Ref CognitoUserPoolClientName, "update"]]
DependsOn: UserPoolResourceServer

Configure Cognito User Pool Domain

To generate the token, we must have a valid domain name configured with our AWS Cognito User Pool. You can configure your domain name, or you can choose a domain from AWS.

UserPoolDomain: 
Type: AWS::Cognito::UserPoolDomain
Properties:
UserPoolId: !Ref MyCognitoUserPool # Refferencing Congnito User Pool domain name parameter.
Domain: !Ref CognitoUserPoolDomain

Configure User Pool Resource Server.

Configurations for Cognito user pool resource server.

UserPoolResourceServer: 
Type: AWS::Cognito::UserPoolResourceServer
Properties:
UserPoolId: !Ref MyCognitoUserPool
Identifier: !Ref CognitoUserPoolResourceServerIdentifier
Name: !Ref CognitoUserPoolResourceServerName
Scopes:
- ScopeName: "create"
ScopeDescription: "create"
- ScopeName: "update"
ScopeDescription: "update"

Configure API Gateway.

Since we will use OAuth 2.0 as the authentication mechanism, wh have to use the AWS::Serverless::HttpApi resource type when creating the API gateway.

MyApi:
Type: AWS::Serverless::HttpApi
Properties:
StageName: Prod
CorsConfiguration:
AllowOrigins:
- "http://*"
- "https://*"
AllowHeaders:
- authorization
AllowMethods:
- GET
MaxAge: 3600
Auth:
DefaultAuthorizer: JWTTokenAuthorizer
Authorizers:
JWTTokenAuthorizer:
JwtConfiguration:
issuer: !Sub https://cognito-idp.${AWS::Region}.amazonaws.com/${MyCognitoUserPool}
audience:
- !Ref MyCognitoUserPoolClient
IdentitySource: "$request.header.Authorization"

Configure the AWS Lambda function.

HelloWorldFunction: # You can use any name that you preffered.
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/ # Source code folder.
Handler: app.lambdaHandler
Runtime: nodejs12.x
Role: !Ref IAMExecutionRole # Lambda execution role.
Events:
HelloWorld:
Type: HttpApi
Properties:
ApiId: !Ref MyApi # Refferencing API Gateway configurations.
Path: /hello # API path
Method: get # HTTP method

Configure buildspec.yml file

When configuring the AWS CI/CD pipeline, you need to have a repository and instructions to execute when you need to build and store the artifacts. In buildspec.yaml you can configure all the build instructions that you need to execute.

version: 0.1
phases:
install:
commands:
- aws cloudformation package --template-file template.yaml --s3-bucket ADD_YOUR_BUCKET_NAME_HERE --output-template-file outputSamTemplate.yaml
artifacts:
type: zip
files:
- template.yaml
- outputSamTemplate.yaml

Configure CI/CD pipeline (AWS CodePipeline)

Please configure a CI/CD in the pipeline AWS CodePipeline and add the below configuration to the CI/CD Pipeline as overridden parameters.

{
"IAMExecutionRole": "",
"CognitoUserPoolName": "",
"CognitoUserPoolClientName": "",
"CognitoUserPoolDomain": "",
"CognitoUserPoolResourceServerName": "",
"CognitoUserPoolResourceServerIdentifier": ""
}

GitHub link

--

--