How to implement NestJS Passport Authentication using Local Strategy?
Tags: javascript, typescript, passport, nestjs
Published: 2022-01-08 03:35:29

In this post, we will learn how to implement **NestJS Passport Authentication** using the passport local strategy. Authentication is a key aspect of any production-level application. While there are many ways to handle authentication, one of the more popular ways is to use Passport.

If you are new to NestJS in general, you can start by going through this post on [NestJS Basics](https://progressivecoder.com/nestjs-basics-core-fundamentals-learn-nestjs-series-part-1/). However, if you are mainly interested in learning how to get started with authentication in NestJS, you can continue with this post.

## 1 – What is Passport?
**Passport is a popular NodeJS library**. It is used for authentication purpose and comes along with several strategies. These strategies basically implement different authentication mechanism. For our example, we will use the local strategy. This strategy makes use of username and password.


![Authentication](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xhxk8sf7e6bkhvztbd8u.jpeg)

Passport executes a series of steps as below:

- Authenticating a user by its credentials. These credentials can be username/password, JWT tokens or any other identity token.
- Manage authentication state by issuing a JWT token.
- Attach information about the user to the Request object.
- To make things easy, the `@nestjs/passport` module wraps the entire passport usage pattern into familiar NestJS constructs. This makes it extremely easy to implement NestJS Passport Authentication.

## 2 – Install Packages
To enable the local strategy, we need to install the required packages as below:

```
$ npm install --save @nestjs/passport passport passport-local
$ npm install --save-dev @types/passport-local
```

Passport provides the passport-local strategy that implements the username/password authentication. Also, we install the `@nestjs/passport` and the passport packages. Finally, the `@types/passport-local` package helps us with Typescript types during development.

_Note - For any strategy, we need to always install the @nestjs/passport and the passport packages. The third package depends on the strategy we are trying to implement. For the local strategy, we install passport-local. Similarly, for the JWT strategy, we use the `passport-jwt` strategy. Even the types package depends on the strategy._

With the installation done, let’s now begin building our application.

## 3 – Creating the Modules
As a first step, let’s divide our application into appropriate modules. We will creating an **auth-module** and **users-module**. Basically, the **auth-module** will contain the logic for authenticating the user. On the other hand, the **users-module** will contain the user information.

With this view, we will create both the modules and their associated services as below:

```
$ nest g module auth
$ nest g service auth
$ nest g module users
$ nest g service users

```
Next step is to build our passport strategy. Configuring a strategy has two typical steps as below:

- First is a set of options that are specific to a particular strategy. For example, the JWT strategy needs a secret to sign the tokens.
- Second is a verify callback. In other words, we tell passport how to verify whether a user is valid. Passport expects this callback to return the full user object if the validation is successful. Also, it should return null if validation fails. Failure can mean that the user does not exist. For a strategy like **passport-local**, it can also mean that the password is invalid.

The NestJS passport package helps with the above two steps by providing helper classes.

## 4 – Implementing the User Service
Let’s first create the user service. See below example:

```
import { Injectable } from '@nestjs/common';

export type User = any;

@Injectable()
export class UsersService {

    private readonly users = [
        {
            userId: 1,
            username: 'John Marston',
            password: 'rdr1',
        },
        {
            userId: 2,
            username: 'Arthur Morgan',
            password: 'rdr2',
        },
    ]

    async findOne(username: string): Promise<User | undefined> {
        return this.users.find(user => user.username === username)
    }
}
```

For our demo example, our user service will simply contain a list of hardcoded valid users. However, for a real application, we would probably create a user database and fetch the users from the appropriate table using [NestJS TypeORM](https://progressivecoder.com/how-to-configure-nestjs-typeorm-integration-mysql/) or [NestJS Sequelize libraries](https://progressivecoder.com/how-to-setup-a-nestjs-sequelize-postgresql-integration/). You can also using MongoDB using the [NestJS Mongoose](https://progressivecoder.com/how-to-build-a-nestjs-mongodb-crud-application-using-mongoose/) library.

In the above example, the `findOne()` method simply fetches the user from the users array. Also, we need to update the exports array for the **UsersModule** as below:

```
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';

@Module({
  providers: [UsersService],
  exports: [UsersService]
})
export class UsersModule {}
```

## 5 – Implementing the Auth Service
As the next step, we implement the Auth Service in the Auth Module.

See below:

```
import { Injectable } from '@nestjs/common';
import { UsersService } from 'src/users/users.service';

@Injectable()
export class AuthService {
    constructor(private usersService: UsersService){}

    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.findOne(username);

        if (user && user.password === password) {
            const {password, ...result} = user
            return result
        }
        return null
    }
}
```

Basically, the auth service has the job of retrieving the user and verifying the password. As you can see, we create the `validateUser()` method. We fetch the user by using the user service and return the user object as output. However, we strip the password property out of the object before returning it.

Finally, we update the **AuthModule** to import the **UsersModule**. Without this step, we will not be able to use the user service in the auth module.

```
import { Module } from '@nestjs/common';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';

@Module({
  imports: [UsersModule],
  providers: [AuthService]
})
export class AuthModule {}
```

## 6 – Implement Passport Local Strategy
This is a key step in implementing the NestJS Passport Authentication.

Basically, we need to implement the passport local strategy. To do so, we create a file named **local.strategy.ts** in the auth folder.

```
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy } from "passport-local";
import { AuthService } from "./auth.service";

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
    constructor(private authService: AuthService) {
        super()
    }

    async validate(username: string, password: string): Promise<any> {
        const user = await this.authService.validateUser(username, password);

        if (!user) {
            throw new UnauthorizedException();
        }

        return user;
    }
}
```

Basically, we create a class **LocalStrategy** that extends the **PassportStrategy** class. We also pass the attribute Strategy in the class definition. Note here that the **Strategy** is imported from **passport-local** and not passport package.

In the constructor, we simply call the `super()` method. The local strategy only expects the username and password fields and therefore, configuration options are not needed. However, if needed, we can pass extra properties while calling super().

Next, we implement the `validate()` method as part of the **PassportStrategy** class. For every strategy, Passport will call the verify function. In NestJS, this function is implemented with the `validate()` method. Based on the strategy, it expects some arguments. For example, in the local strategy, it expects the username and password attributes.

From a logical point of view, this method is quite simple. It simply calls the `validateUser()` method from the Auth service. If a valid user is found, it returns the same. Otherwise, it throws an exception. Most of the heavy work is done in the Auth Service.

Lastly, we need to update the Auth Module as below to use the passport module.

```
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';

@Module({
  imports: [UsersModule, PassportModule],
  providers: [AuthService, LocalStrategy]
})
export class AuthModule {}
```

## 7 – Creating the Login Route
Now, we can create the login route. Basically, this route will be used to authenticate a user.

```
import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Controller()
export class AppController {
  
  @UseGuards(AuthGuard('local'))
  @Post('login')
  async login(@Request() req) {
    return req.user;
  }
}
```

As you can see, we use the standard `@Controller()` decorator. Also, we use `@Post()` for the `login()` request handler. If you wish to know more about creating controllers, you can refer to our detailed post on [NestJS Controllers](https://progressivecoder.com/creating-your-first-nestjs-controller-learn-nestjs-series-part-2/).

Important thing to note here is the @UseGuards(AuthGuard(‘local’)) decorator. Basically, the AuthGuard is a special guard provided by the @nestjs/passport package. This guard was provisioned when we extended the **passport-local** strategy.

This built-in guard invokes the Passport strategy and starts the entire process. In other words, based on the strategy in the **AuthGuard** (in this case, local), this guard will retrieve the credentials, run the verify function and create the user property.

The user can simply authenticate by using the `/login` route as below:

```
$ curl -X POST http://localhost:3000/auth/login -d '{"username": "John Marston", "password": "rdr1"}' -H "Content-Type: application/json"
```

In case the user is valid, we receive the user object in response. Else, we receive the HTTP Status 401 or **Unauthorized**.

## Conclusion
With this, we have successfully learnt how to implement **NestJS Passport Authentication using the passport local strategy**.

We started by installing the required packages and then building the modules for retrieving users and authenticating them. Lastly, we implemented the login route to trigger the passport authentication process.

The code for this post is available on [Github](https://github.com/dashsaurabh/nestjs-authentication-demo).

In the next post we will be implementing the [NestJS Passport JWT Strategy](https://progressivecoder.com/how-to-implement-nestjs-jwt-authentication-using-jwt-strategy/).

If you have any comments or queries, please feel free to mention them in the comments section below.