wrapperjs-auth4

How to add Amazon Cognito Auth to a Web App (part 4)

Looking at the NodeJS logic that is run in lambda functions to power the Back End of Amazon Cognito Authentication.

Table of Contents

Intro

In myย last post, I explained how Amazon Cognito is integrated into the Front End, to allow content to become visible to users that have gone through the Auth process as shown in the below demo ๐Ÿ‘‡

In this post, I’ll explain how this same process can be implemented in the Back End.

If you look at the right side of the above gif, you will see an open console log. Please note the ‘Hello World!! ๐Ÿ˜€‘ message that appears in the logs once the user has successfully signed in.

This message is returned to users, that have logged into the Front End and then gone through the Auth process on the Back End.

Implementing Cognito Auth on the Back End

I have aย Wrapper.js templateย that you can use to spin up an implementation of Cognito, here are some highlight files from that template:

serverless/serverless.common.yml

				
					service: ${file(./../../../serverless.env.json):service_name}-${file(./../../../serverless.env.json):stage}

provider:
  environment: ${file(./../../../serverless.env.json)}
  name: aws
  region: ${file(./../../../serverless.env.json):region}
  runtime: nodejs12.x
  stage: ${file(./../../../serverless.env.json):stage}
  apiGateway: # Optional API Gateway global config
    restApiId: ${file(./../../../serverless.env.json):api_gateway_rest_api_id} # REST API resource ID. Default is generated by the framework
    restApiRootResourceId: ${file(./../../../serverless.env.json):api_gateway_root_resource_id} # Root resource ID, represent as / path
  iam:
    role:
      statements:
        - Effect: Allow
          Action:
            - dynamodb:Query
            - dynamodb:Scan
            - dynamodb:GetItem
            - dynamodb:PutItem
            - dynamodb:UpdateItem
            - dynamodb:DeleteItem
          Resource: "*"
        - Effect: Allow
          Action:
            - "execute-api:ManageConnections"
          Resource:
            - "arn:aws:execute-api:*:*:**/@connections/*"

custom:
  apiAuthorizer: 
    id : ${file(./../../../serverless.env.json):cognito_authorizer}
  serverless-offline:
    host: '0.0.0.0'   
				
			

Serverless Framework in WrapperJS is organised into HTTP and Websocket services, each service has its own yaml configuration.

Variables that are exported from Terraform (the cognito details) are passed to the above file, which the individual services can then reference.

These variables are:

  • restApiId: the ID of the API Gateway that Serverless Framework should deploy lambda end points to
  • ย restApiIdRootResourceId: the root path of that API Gateway, that all lambda endpoints will be added to
  • apiAuthorizer: an API Authorizer that was created by Terraform from the ARN of the Cognito User Pool

serverless/services/http/users/serverless.yml

				
					service: ${file(./../../../serverless.common.yml):service}-${self:custom.service}
useDotenv: true

provider: ${self:custom.common.provider}

functions:
  - ${file(userData/lambda.yml)}

plugins:
  - serverless-offline
  
custom:
  service: users-service
  common: ${file(./../../../serverless.common.yml)}
  apiAuthorizer: ${self:custom.common.custom.apiAuthorizer.id}
  serverless-offline: ${self:custom.common.custom.serverless-offline}
				
			

In lines 4 and 15 of the Users service’s yaml (our demo service), you can see the configurations declared in the previous file being set in this service.

serverless/services/http/users/userData/lambda.yml

				
					getUserData:
  handler: userData/index.handler
  events:
    - http:
        path: users/data
        method: get
        integration: lambda
        authorizer: 
          type: COGNITO_USER_POOLS
          authorizerId: ${self:custom.apiAuthorizer}
        cors:
          origin: '*'
          headers: # <-- Specify allowed headers
            - Content-Type
            - Authorization
				
			

The configuration for the users/data endpoint (our test endpoint) is configured to return data if the Front End provides the authorizer that has been defined in lines 8-10.

serverless/services/http/users/userData/index.js

				
					'use strict';

module.exports.handler = async(event, context, callback) => {
  const response = {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Credentials': true
    },
    body: 'Hello World!! :D'
  };
  callback(null, response);
};
				
			

Finally, this is the lambda that is executed when the end point has been called and the appropriate authorisation is provided.

The function returns a body of ‘Hello World!! ๐Ÿ˜€‘.

Conclusion

So that is it, the end of the 4 part tutorial series!!!!

I hope this has been helpful for you in understanding how to use Amazon Cognito on the Back End for Lambda functions in Serverless Framework.

Feel free to use the template I created for Wrapper.js to spin this up and give it a go!!

In the meantime, go build cool stuff and have fun ๐Ÿ˜€

Share this post