can't access validate function using nestjs jwt+passport auth

52 views Asked by At

here's my study project codes. im trying to nestjs+jwt+passport. however, no matter what method i use, i get a 401 Unauthorized error. i cant even access the validate function, and when i try to console.log, it doesnt appear... im sorry to ask you this question, and thanks for everybody's help

auth.controller.ts

import { Body, Controller, Get, Post, Req, UnauthorizedException, UseGuards } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { LoginDTO } from 'src/user/login.dto';
import { UserService } from 'src/user/user.service';
import { AuthGuard } from './auth.guard';

@Controller()
export class AuthController {
    constructor(
        private readonly userService: UserService,
        private readonly jwtService: JwtService
    ) {}

    @Post('/signin')
    async signin(@Body() loginDTO: LoginDTO) {
        const user = await this.userService.findByLogin(loginDTO);

        if (!user) {
            throw new UnauthorizedException('check again');
        }

        const accessToken = this.jwtService.sign({ email: loginDTO.email });

        return { accessToken: accessToken };
    }

    @UseGuards(AuthGuard)
    @Get('/test')
    async getProfile(@Req() req) {
        const user = req.user;
        return user;
    }
}

auth.passport.jwt.ts

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { UserService } from 'src/user/user.service';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
    constructor(private userService: UserService) {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: true,
            secretOrKey: `${process.env.AUTH_SECRET_KEY}`
        });
    }

    async validate(payload: { email: string }) {
        const { email } = payload;
        const user = await this.userService.findByEmail(email);

        if (!user) {
            throw new UnauthorizedException({ message: 'null' });
        }

        return user;
    }
}

auth.module.ts

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller';
import { UserModule } from 'src/user/user.module';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './auth.passport.jwt';

@Module({
    imports: [
        JwtModule.register({
            secret: `${process.env.AUTH_SECRET_KEY}`
        }),
        UserModule,
        PassportModule
    ],
    controllers: [AuthController],
    providers: [JwtStrategy]
})
export class AuthModule {}

auth.guard.ts

import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard as NestAuthGuard } from '@nestjs/passport';

@Injectable()
export class AuthGuard extends NestAuthGuard('jwt') {
    canActivate(context: ExecutionContext) {
        return super.canActivate(context);
    }
}

I've tried using AuthGuard() from @nestjs/passport instead of AuthGuard in the controller's @UseGuards(AuthGuard) section, but the same error occurs.

2

There are 2 answers

0
levi On

the problem comes from the fact that in your authControler in the getProfil method, you retrieve the user from the request without specifying its type. replace :

@UseGuards(AuthGuard)
@Get('/test')
async getProfile(@Req() req) {
    const user = req.user;
    return user;
}

with:

@UseGuards(AuthGuard)
@Get('/test')
async getProfile(@Req() req: Request) {
    const user = req.user;
    return user;

import Request like:

import { Request } from 'express';

Here are some tips to adopt to properly organize your code: Replace :

JwtModule.register({
        secret: `${process.env.AUTH_SECRET_KEY}`
    }),

with in your authModule, because you have already specified this in the strategy:

JwtModule.register({}) 

You don't need to create the AuthGuard class, because nestjs through passport already integrates this. In your controler import the AuthGuard from:

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

when you also generate an accessToken, you must always specify a duration and secret:

const accessToken = this.jwtService.sign({ email: loginDTO.email }, {
    secret: `${process.env.AUTH_SECRET_KEY}`,
    expiresIn: '15m',
  });

finally replace replace:

ignoreExpiration: true,

with ignoreExpiration: false,

If this solved your problem, please mark my answer as the solution. good continuation

0
nyoto arif On

This solution work for my case:

The problem is jwt.sign(token) did not sign using the secret I have supplied in the Module constructor.

Try to first verify by generating a jwt token from jwt.io (with your SECRET_TOKEN) and then feed it to your service. If that works -> your jwt.verify() is at least working properly.

Then try to generate jwt token from your service by calling jwt.sign(token, {secret: SECRET_TOKEN}). Validate the signed token in jwt.io and through your service.