JWTGuard always returning 401 unauthorized when using the correct token

59 views Asked by At

I am a beginner in Nestjs When using JWTGuard in my user controller for all my CRUD operations it returns always 401 unauthorized error This is my JWT Strategy

import { PassportStrategy } from "@nestjs/passport";
import { JwtPayload } from "jsonwebtoken";
import { ExtractJwt, Strategy } from "passport-jwt";

export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
    constructor() {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            secretOrKey: `${process.env.SECRET}`,
            ignoreExpiration: false,
        });

    }

    async validate(payload: JwtPayload) {
        console.log('JWT Strategy - Validate: ', payload);
        return { user: payload.sub, username: payload.username }
    }
}

This is my authService

import { Injectable } from '@nestjs/common';
import { UserService } from 'src/user/user.service';
import * as bcrypt from 'bcrypt'
import { User } from 'src/user/schemas/user_schema';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {

    constructor(
        private readonly userService: UserService,
        private jwtService: JwtService) { }

    async validateUser(email: string, password: string) {

        const user = await this.userService.findOneWithEmail(email)
        if (user && await bcrypt.compare(password, user.password)) {
            const { password, ...result } = user
            return result;
        }
        return null;
    }

    async login(user: User) {
        const payload = {
            username: user.email,
            sub: {
                name: user.name
            }
        }

        user.password = undefined
        return {
            ...user,
            accessToken: this.jwtService.sign(payload),
            refreshToken: this.jwtService.sign(payload, { expiresIn: '1d' }),
        }
    }
    async refreshToken(user: User) {
        const payload = {
            username: user.email,
            sub: {
                name: user.name,
            },
        };

        return {
            accessToken: this.jwtService.sign(payload),
        };
    }
}

This is my user controller

import { Controller, Get, Post, Body, Patch, Param, Delete, ValidationPipe, UsePipes, Res, Redirect, Request, UseGuards, Query } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { JwtGuard } from 'src/auth/guards/jwt-auth.guard';
import { AuthService } from 'src/auth/auth.service';
import { Query as ExpressQuery } from 'express-serve-static-core';

@Controller('user')
export class UserController {
  constructor(
    private readonly userService: UserService,
    private authService: AuthService) { }

  @Post('register')
  @UsePipes(new ValidationPipe({ transform: true }))
  register(@Body() createUserDto: CreateUserDto) {
    return this.userService.register(createUserDto);
  }

  @Post('login')
  @UsePipes(ValidationPipe)
  @Redirect('/auth/login')
  async login(@Request() req) { }

  @UseGuards(JwtGuard)
  @Get()
  findAll(@Query() query: ExpressQuery) {
    return this.userService.findAll(query);
  }

  @UseGuards(JwtGuard)
  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.userService.findOne(id);
  }

  @UseGuards(JwtGuard)
  @Patch()
  update(@Body() updateUserDto: UpdateUserDto) {
    return this.userService.update(updateUserDto);
  }

  @UseGuards(JwtGuard)
  @Delete(':id')
  remove(@Param('id') userId: string, @Body('id') deleteId: string) {
    return this.userService.remove(userId, deleteId);
  }
}

This my userModule

import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { JwtModule } from '@nestjs/jwt';
import { User, UserSchema } from './schemas/user_schema';
import { MongooseModule } from '@nestjs/mongoose';
import { PasswordService } from 'src/password/password.service';
import { JwtStrategy } from 'src/auth/strategies/jwt-strategy';
import { AuthModule } from 'src/auth/auth.module';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from 'src/auth/auth.service';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
    JwtModule.register({
      secret: `${process.env.SECRET}`,
      signOptions: { expiresIn: '1h' },
    }),
    AuthModule,

  ],
  controllers: [UserController],
  providers: [UserService, PasswordService, JwtStrategy, PassportModule, AuthService],
})
export class UserModule { }

and this is my

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UserService } from 'src/user/user.service';
import { JwtModule, JwtService } from '@nestjs/jwt';
import { LocalStrategy } from './strategies/local-strategies';
import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from 'src/user/schemas/user_schema';
import { PasswordService } from 'src/password/password.service';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './strategies/jwt-strategy';
import { RefreshJwtStrategy } from './strategies/refreshToken.strategy';

@Module({
  providers: [
    AuthService,
    UserService,
    LocalStrategy,
    PasswordService,
    JwtStrategy,
    RefreshJwtStrategy
  ],
  controllers: [AuthController],
  imports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
    JwtModule.register({
      secret: `${process.env.SECRET}`,
      signOptions: { expiresIn: '1d' },
    }),
    PassportModule],
  exports: [AuthService, LocalStrategy, JwtStrategy],

})
export class AuthModule { }

Knowing that the local guard works fine with the login to my knowledge

I have tried rechecking the token making sure that the .env file works properly

1

There are 1 answers

0
Ali Hajiloo On

in the passport you just allow to use function verify(username, password) you can't use email

the only way is change username field name is this:

export class LocalStrategy extends PassportStrategy(Strategy, 'jwt') {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: `${process.env.SECRET}`,
      ignoreExpiration: false,
      usernameField: 'email',
      passwordField: 'password',
    });
  }

 async validate(
    email: string,
    password: string,
  ): Promise<any> {
     if(password === true){
     console.log('JWT Strategy - Validate: ', payload);
     return { user: payload.sub, username: payload.username }
     }
   }
}