5

I am begginer at Nestjs.

I trying to get access-token from login route. I followed the exact steps shown in NestJs Authentication docs. But I getting 401 unauthorized every time. I am frustrated at this point. If someone could help me to get the access-token, it would be great.

Here auth.module.ts

import { JwtStrategy } from './jwt.strategy';
import { UserModule } from './../user/user.module';
import { ConfigModule } from '@nestjs/config';
import { Module, forwardRef } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from './local.strategy';

@Module({
  imports: [
    forwardRef(() => UserModule),
    PassportModule,
    ConfigModule,
    JwtModule.registerAsync({
      useFactory: () => ({
        secret: process.env.JWT_SECRET,
        signOptions: { expiresIn: '1d' },
      }),
    }),
  ],
  providers: [AuthService, LocalStrategy, JwtStrategy],
  exports: [AuthService],
})
export class AuthModule {}

here auth.service.ts

import { UserService } from './../user/user.service';
import { forwardRef, Inject, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';

@Injectable()
export class AuthService {
  constructor(
    private jwtService: JwtService,
    @Inject(forwardRef(() => UserService))
    private userService: UserService,
  ) {}

  hashPassword(password: string): Promise<string> {
    return bcrypt.hash(password, 12);
  }

  comparePassword(
    newPassword: string,
    passwordHash: string,
  ): Promise<any | boolean> {
    return bcrypt.compare(newPassword, passwordHash);
  }

  async validateUser(username: string, password: string): Promise<any> {
    const user = await this.userService.findOne(username);
    const match = await this.comparePassword(password, user.password);
    if (user && match) {
      const { id, name, email, mobile, role } = user;
      return { id, name, email, mobile, role };
    }
    return null;
  }

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

local.strategy.ts

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;
  }
}

local-auth.guard.ts

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

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

user.controller.ts

import { AuthService } from './../auth/auth.service';
import { UserService } from './user.service';
import { Body, Controller, Post, Request, UseGuards } from '@nestjs/common';
import { RegisterUserDto } from './user.dto';
import { LocalAuthGuard } from 'src/auth/local-auth.guard';

@Controller('user')
export class UserController {
  constructor(
    private authService: AuthService,
    private userService: UserService,
  ) {}
  @Post('/register')
  register(@Body() body: RegisterUserDto): Promise<any> {
    return this.userService.registerUser(body);
  }

  @UseGuards(LocalAuthGuard)
  @Post('/login')
  async login(@Request() req): Promise<any> {
    return this.authService.login(req.user);
  }
}

enter image description here

1 Answers1

5

The problem is the signature of validate method, on LocalStrategy class. Make sure it receives exactly username and password.

If you replace username with email or something else it will not overload the original PassportStrategy method, returning always Unauthorized, given no clue of the error.

Abdellatif B
  • 61
  • 1
  • 2