3-how-to-create-a-secure-api-with-nestjs-and-jwt-authentication.html

How to Create a Secure API with NestJS and JWT Authentication

In the world of web development, security is paramount, especially when creating APIs that handle sensitive data. One of the most effective ways to secure your API is through the use of JSON Web Tokens (JWT). NestJS, a powerful framework built on Node.js, simplifies the development of scalable and maintainable server-side applications. In this article, we will guide you through the process of creating a secure API using NestJS and JWT authentication.

What is NestJS?

NestJS is a progressive Node.js framework that enables developers to build efficient and scalable server-side applications. It leverages TypeScript and incorporates elements from OOP (Object-Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming). NestJS is particularly well-suited for building APIs, microservices, and server-rendered applications.

What is JWT Authentication?

JSON Web Tokens (JWT) are an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs are commonly used for authentication and information exchange in distributed systems.

Use Cases for JWT Authentication

  • Single Sign-On (SSO): Allows users to log in once and gain access to multiple applications.
  • Stateless Authentication: No need to store sessions on the server, making it easy to scale.
  • Mobile Applications: Securely authenticate users on mobile platforms.

Setting Up Your NestJS Project

Let's start by creating a new NestJS project. Make sure you have Node.js and npm installed on your machine.

Step 1: Install NestJS CLI

Open your terminal and run the following command to install the NestJS CLI globally:

npm install -g @nestjs/cli

Step 2: Create a New Project

Now, create a new NestJS project by executing:

nest new secure-api

Navigate into your project directory:

cd secure-api

Step 3: Install Required Packages

For JWT authentication, you'll need to install the following packages:

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

Implementing JWT Authentication

Now that we have our project and dependencies set up, let's implement JWT authentication.

Step 4: Create Auth Module

Generate an authentication module:

nest generate module auth

Step 5: Create Auth Service

Next, create an authentication service:

nest generate service auth

Open auth.service.ts and implement the following:

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { User } from './user.entity'; // Assume you have a User entity
import * as bcrypt from 'bcryptjs';

@Injectable()
export class AuthService {
  constructor(private jwtService: JwtService) {}

  async validateUser(username: string, password: string): Promise<any> {
    // Replace this with your database logic
    const user: User = await this.findUserByUsername(username); 
    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (user && isPasswordValid) {
      const { password, ...result } = user;
      return result;
    }
    return null;
  }

  async login(user: any) {
    const payload = { username: user.username, sub: user.userId };
    return {
      access_token: this.jwtService.sign(payload),
    };
  }

  private async findUserByUsername(username: string): Promise<User> {
    // Implement your user retrieval logic here
  }
}

Step 6: Create Auth Controller

Generate a controller for authentication:

nest generate controller auth

Open auth.controller.ts and add the following code:

import { Controller, Post, Body, Request } from '@nestjs/common';
import { AuthService } from './auth.service';

@Controller('auth')
export class AuthController {
  constructor(private authService: AuthService) {}

  @Post('login')
  async login(@Body() req: { username: string; password: string }) {
    return this.authService.login(req);
  }
}

Step 7: Configure JWT Module

Open your app.module.ts file and import the JWT module:

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthModule } from './auth/auth.module';

@Module({
  imports: [
    AuthModule,
    JwtModule.register({
      secret: 'yourSecretKey', // Replace with your secret
      signOptions: { expiresIn: '60s' }, // Token expiration
    }),
  ],
})
export class AppModule {}

Step 8: Implement Passport Strategy

Create a JWT strategy to handle token validation:

nest generate service jwt.strategy

Open the newly created strategy file and implement the following:

import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from './auth.service';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: 'yourSecretKey', // Should match the JWT module secret
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

Step 9: Securing Routes

To secure your routes, you can use guards provided by NestJS. Simply decorate your routes with the @UseGuards(AuthGuard('jwt')) decorator.

import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Controller('profile')
export class ProfileController {
  @UseGuards(AuthGuard('jwt'))
  @Get()
  getProfile() {
    return { message: 'This is a protected route' };
  }
}

Conclusion

You’ve now built a secure API using NestJS and JWT authentication! By following these steps, you’ve learned how to set up a basic NestJS application, implement JWT authentication, and secure your API endpoints.

Key Takeaways

  • NestJS provides a robust framework for building scalable applications.
  • JWT is a powerful tool for secure authentication.
  • Always ensure your secret keys are stored securely and not hardcoded in your source code.

Next Steps

  • Explore integrating role-based access control (RBAC) with JWT.
  • Consider using environment variables for sensitive information.
  • Experiment with different authentication strategies.

With these practices, you can enhance the security and scalability of your applications while providing a seamless user experience. Happy coding!

SR
Syed
Rizwan

About the Author

Syed Rizwan is a Machine Learning Engineer with 5 years of experience in AI, IoT, and Industrial Automation.