Using AWS Cognito with NestJS

AWS Cognito simplified the authentication, authorization and user management for you. In this post I will try to present how we can use this authentication service with your mobile app, website, and manage users.

Initial work

To get started with AWS Cognito We need to create a user pool. The user pool is a container that AWS Cognito uses to manage and hold users identify.

We are going to start with Create User Pool. In my case I don’t have user pools, so I’m going to create one.

Here you are given two options to select from, let’s select Review defaults. Make sure to provide a pool name as well.

Next, we need to create an app client. The app client is the client that our NestJS server will be communicating with. Make sure to tick Enable sign-in API for server-based authentication for our NodeJS server access Cognito user pool for authentication. App clients can be created after the generation of user pools as well. So, if you forget to add an app client when the creation of the user pool - do not worry, you can create a new one again.

Let’s take a look at the overview of the settings, it should look like mine.

Creating TypeScript NestJS Server

Ok, once we have completed the first part of the post which was creating a User Pool in Amazon Cognito, we can switch to creating the NestJS server which will use the Amazon Cognito user pool to authenticate users.

The easiest way to set up the environment is to run commands to initialize the Nest app and allow us to install the required packages.

I describe using npm to install packages, including the Nest CLI. Install the CLI globally using the npminstall-g command (see the note above for details about global installs).

So, we are adding the Nest CLI package globally:

npm install -g @nestjs/cli

To create, build and run a new basic Nest project in the development mode, go to the folder that should be the parent of your new project, and run the following commands:

nest new simple-app
cd simple-app
npm run start:dev

In your browser open http://localhost:3000 to see a new application running. The app will automatically recompile and reload when you change any of the source files.

Implement authentication

We are going to implement three functions in our NodeJS server application that authenticate the user:

Sign in

Sign up

Token Validation (bonus, as an Authentication middleware)
For each function we will need separate API endpoints in our server as well. Let’s create an auth.controller to handle incoming requests.

For that purpose we are going to use NestCLI to generate the auth.module, auth.controller and auth.service.

The Nest CLI automatically will generate the auth folder with files and add it to the existing app module.

The next step is to add a package to help us reach the Cognito SDK which will be going to be used for requests to Cognito API

npminstallamazon-cognito-identity-js--save

In auth.service we define the CognitoUserPool by giving generated userPoolId, appClientId. For safety reasons, it’s good to store them in the config file. Then I’ve added the function for register and authenticate.

In case you want to check the decoded jwt you can check this out. More about verifying JWT in Cognito User Pool you can find here.

When you want to use the Authentication Guard. Guards have a single responsibility. They determine whether a given request will be handled by the route handler or not, depending on certain conditions (like permissions, roles, ACLs, etc.) present at run-time. This is often referred to as authorization. Authorization (and its cousin, authentication, with which it usually collaborates) has typically been handled by middleware in traditional Express applications. Middleware is a fine choice for authentication, since things like token validation and attaching properties to the request object are not strongly connected with a particular route context (and its metadata).

We need to use AuthGuard and use Decorator @UseGuards(AuthGuard). More about decorators you can find here.

It’s showtime!

The above code is a minimalistic version for NestJS authentication using Cognito User Pools. Now it’s time for doing some tests.

1. Register

I used Postman to send the request. In @Body I included email, password, name. A created successful response will contain:

Then we can check also in our app in Cognito that the User has been created:

2. Authenticate

Again, in @Body I sent the required password and the user field. If I prepare the correct data, I will receive the user payload:

3. Validation

For the test purposes I have added the Guard for the demo route. If I don’t include the Authorization header with a token, the server will throw UnauthorizedException and in the client I will receive:

{"statusCode":401,"error":"Unauthorized"}

When we add in a proper format the token Bearer {token} the Guard which will determine that the token is valid or not, and will allow the route to handle the request.

Summary

I think that more and more developers will use the IaaS (infrastructure as a service) and move logic outside the backend. What is great, in AWS you can also move all the logic with verifying the JWT to LAMBDA which can be triggered before sign-up and authentication (we can customize these workflows in the user pool settings).

Cognito is a great service from AWS. I’m using it always when I have an opportunity to do it.