Sling Academy
Home/Node.js/How to Handle Authentication and Authorization in NestJS

How to Handle Authentication and Authorization in NestJS

Last updated: December 31, 2023

Introduction

Handling authentication and authorization is a critical component in modern web applications. This tutorial dives into best practices for managing these security features within a NestJS application, with the latest TypeScript syntax in play.

Setting Up Your NestJS Project

Before diving into authentication and authorization, initialize your NestJS project by running:

nest new project-name

After creating the project, navigate to its directory:

cd project-name

Implementing Authentication with Passport

NestJS leverages Passport.js for authentication. First, install the required packages:

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

Create an auth module, service, and a local strategy:

nest generate module auth
nest generate service auth
nest generate strategy auth/local

In your local strategy:

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';

class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise {
    // Add your validation logic here
  }
}

For handling user validation, you should implement AuthService:

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

@Injectable()
export class AuthService {
  // Your user validation logic goes here
}

Setting Up JWT for Sessions

To manage sessions with JWT, you’ll need additional packages:

npm install @nestjs/jwt passport-jwt
npm install @types/passport-jwt --save-dev

Implement a JWT strategy similar to the local strategy, using passport-jwt.

Securing Routes with Guards

Authentication isn’t useful without securing routes. Implement a guard to ensure users are authenticated:

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}

Then, apply the guard to your routes using decorators:

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

@Controller()
export class AppController {
  @UseGuards(LocalAuthGuard)
  @Post('auth/login')
  async login(@Request() req) {
    return req.user;
  }
  // ... additional methods ... 
}

Implementing Authorization with Roles

Authorization ensures that authenticated users have permissions to perform certain actions. NestJS supports role-based access control:

import { Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { CanActivate, ExecutionContext } from '@nestjs/common';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
      context.getHandler(),
      context.getClass(),
    ]);
    if (!requiredRoles) {
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    return requiredRoles.some((role) => user.roles?.includes(role));
  }
}

To associate roles with routes, create a custom decorator:

import { SetMetadata } from '@nestjs/common';
export const ROLES_KEY = 'roles';
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);

Then, secure a route with the roles decorator and RolesGuard:

@Roles('admin')
@UseGuards(RolesGuard)
async adminAction() {
  // admin only action
}

In advanced scenarios, you may need to refresh tokens. Provide an endpoint for refresh token generation and a strategy to handle it.

Conclusion

Addressing authentication and authorization in NestJS is fundamental for creating secure applications. This tutorial guides you through setting up basic to advanced strategies within the NestJS framework, equipping you to effectively manage your application’s security with confidence. Always test your implementations and keep your dependencies current to uphold best practices.

Next Article: How to Use WebSockets in NestJS for Real-Time Communication

Previous Article: How to Connect to PostgreSQL in NestJS

Series: Nest.js Tutorials: From Basics to Advanced

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates