Creating a robust authentication system is a critical aspect of web development, ensuring that only authorized users can access certain resources. NestJS, a progressive Node.js framework for building efficient and scalable server-side applications, provides a comprehensive system for implementing authentication. This article will guide you through setting up authentication in a NestJS application using Passport, a popular authentication middleware for Node.js, with a focus on a JWT-based (JSON Web Tokens) strategy for its simplicity and effectiveness in managing sessionless authentication.
Authentication in NestJS
NestJS leverages Passport under the hood for its authentication system, abstracting much of the boilerplate code necessary to implement authentication strategies. Passport supports a wide range of authentication techniques, including OAuth, OpenID, and more. However, for this example, we will focus on JWT, a compact URL-safe means of representing claims to be transferred between two parties.
Setting Up Your NestJS Project
First, ensure you have Node.js installed on your machine. Then, create a new NestJS project by running the following command:
npx @nestjs/cli new nest-auth-example
cd nest-auth-example
Next, install the necessary packages:
npm install @nestjs/passport passport passport-jwt @nestjs/jwt
npm install @types/passport-jwt --save-dev
Implementing JWT Authentication
1. Setting up the Auth Module
Create an auth module and service:
nest generate module auth
nest generate service auth
2. Configuring the JWT Module
In your auth.module.ts
, import the JwtModule
:
import { Module } from "@nestjs/common";
import { JwtModule } from "@nestjs/jwt";
import { AuthService } from "./auth.service";
@Module({
imports: [
JwtModule.register({
secret: "secretKey", // Use a strong secret in production
signOptions: { expiresIn: "60s" },
}),
],
providers: [AuthService],
})
export class AuthModule {}
3. Creating the AuthService
In auth.service.ts
, implement the logic to validate a user and sign tokens:
import { Injectable } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
@Injectable()
export class AuthService {
constructor(private jwtService: JwtService) {}
async validateUser(username: string, pass: string): Promise<any> {
// In a real application, you should validate against data in your database
const user = { id: 1, username: "john", password: "changeme" };
if (user.username === username && user.password === pass) {
const { password, ...result } = user;
return result;
}
return null;
}
async login(user: any) {
const payload = { username: user.username, sub: user.id };
return {
access_token: this.jwtService.sign(payload),
};
}
}
4. Creating the Auth Controller
Generate a controller for handling authentication:
nest generate controller auth
In auth.controller.ts
, add a login route:
import { Controller, Request, Post, UseGuards } from "@nestjs/common";
import { AuthService } from "./auth.service";
import { LocalAuthGuard } from "./local-auth.guard";
@Controller()
export class AuthController {
constructor(private authService: AuthService) {}
@UseGuards(LocalAuthGuard)
@Post("auth/login")
async login(@Request() req) {
return this.authService.login(req.user);
}
}
5. Implementing the Local Strategy
Create a local.strategy.ts
file within the auth directory. This strategy validates user credentials:
import { Strategy } from "passport-local";
import { PassportStrategy } from "@nestjs/passport";
import { Injectable, UnauthorizedException } from "@nestjs/common";
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;
}
}
Remember to register LocalStrategy
and any necessary guards in your auth.module.ts
.
Testing Your Authentication System
To test your authentication system, you can use tools like Postman or cURL to make a request to the /auth/login
endpoint, passing in a username and password. If successful, you’ll receive a JWT token in response.
Conclusion
Implementing authentication in a NestJS application is streamlined and efficient, thanks to the integration with Passport. By following the steps outlined above, you can set up a JWT-based authentication system that is secure, scalable, and ready to be integrated into your NestJS application.
For more detailed insights, check out the original story on JavaScript in Plain English.