0
0
NestjsHow-ToBeginner ยท 3 min read

How to Use Local Strategy in NestJS for Authentication

To use LocalStrategy in NestJS, create a class extending PassportStrategy with the 'local' name, implement a validate method to verify user credentials, and register it as a provider. Then use @UseGuards(AuthGuard('local')) on your login route to authenticate users with username and password.
๐Ÿ“

Syntax

The LocalStrategy class extends PassportStrategy from @nestjs/passport with the 'local' strategy name. The key method is validate(username: string, password: string), which checks user credentials and returns user data if valid or throws an error if not.

This strategy is then used with @UseGuards(AuthGuard('local')) in controllers to protect routes.

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

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
  constructor(private authService: AuthService) {
    super(); // calls passport-local constructor
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}
๐Ÿ’ป

Example

This example shows a complete setup of LocalStrategy in NestJS with a simple AuthService that validates a hardcoded user. The AuthController uses the local guard to protect the login route.

typescript
import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-local';
import { UnauthorizedException } from '@nestjs/common';

@Injectable()
class AuthService {
  private readonly users = [
    { id: 1, username: 'john', password: 'changeme' },
  ];

  async validateUser(username: string, password: string) {
    const user = this.users.find(u => u.username === username && u.password === password);
    if (user) {
      const { password, ...result } = user;
      return result;
    }
    return null;
  }
}

@Injectable()
class LocalStrategy extends PassportStrategy(Strategy, 'local') {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string) {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

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

// Module setup omitted for brevity but must include AuthService, LocalStrategy, AuthController providers and imports.
Output
{"id":1,"username":"john"}
โš ๏ธ

Common Pitfalls

  • Not calling super() in the LocalStrategy constructor causes errors.
  • Forgetting to register LocalStrategy and AuthService as providers in the module.
  • Not returning the user object from validate leads to authentication failure.
  • Using incorrect guard name in @UseGuards(AuthGuard('local')) will not trigger the strategy.
  • Not handling UnauthorizedException properly can cause unclear errors.
typescript
/* Wrong: Missing super() call */
class LocalStrategyWrong extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    // super() missing here
  }
  async validate(username: string, password: string) {
    // ...
  }
}

/* Right: Include super() call */
class LocalStrategyRight extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }
  async validate(username: string, password: string) {
    // ...
  }
}
๐Ÿ“Š

Quick Reference

  • LocalStrategy: Extends PassportStrategy(Strategy, 'local') with validate() method.
  • AuthService: Contains user validation logic.
  • UseGuards: Protect routes with @UseGuards(AuthGuard('local')).
  • UnauthorizedException: Throw when credentials are invalid.
  • Module Setup: Register strategy, service, and controller as providers.
โœ…

Key Takeaways

Extend PassportStrategy with 'local' and implement validate() to check credentials.
Use @UseGuards(AuthGuard('local')) to protect login routes with local strategy.
Always call super() in the LocalStrategy constructor to initialize Passport.
Register LocalStrategy and AuthService as providers in your module.
Throw UnauthorizedException if user validation fails to signal authentication error.