How to get NestJS JWT token request to work?

3.9k views Asked by At

I'm building this API using JWT and NestJS. This is an API for a mobile application so I need the JWT Token to be constantly refreshed. The idea is to check the incoming token request, if the token is expired, JWT will thrown an error message saying token expired. If that's the case the token will be refreshed, if it's another error it will throw an error.

I also have a GetUser decorator that would return the user from the HttpRequest, but now that I'm using a custom AuthGuard I can't get it to work. Any tips?

AuthGuard.ts

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { LoginService } from 'src/users/login.service';

@Injectable()

export class AuthGuard implements CanActivate {

    constructor(
        private loginService: LoginService,
        private jwtService: JwtService
    ) {}

    async canActivate( context: ExecutionContext ) {
        const request = context.switchToHttp().getRequest();
        const { headers } = request;

        const headerString = headers.authorization.split(' ');

        const currentToken = await this.loginService.validateToken(headerString[1]);

        return currentToken ? true : false;

    }

}

LoginService.ts

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService, JwtSignOptions } from '@nestjs/jwt';

@Injectable()
export class LoginService {
    constructor(
        private jwtService: JwtService
    ) { }

    async validateToken(token: string): Promise<any> {
        try {
            const verifiedToken = await this.jwtService.verify(token, { secret: process.env.JWT_SECRET });
            return verifiedToken;
        } catch (error) {
            if (error.message === 'jwt expired' ) {
                const newToken = await this.refreshToken(token);
                return newToken;
            } else {
                throw new UnauthorizedException();
            }
        }
    }

    async refreshToken(token: string | any ): Promise<any> {
        const decodedToken = await this.jwtService.decode(token) as any;
        const { email, id } = decodedToken;;
        const payload = { email, id };
        const options: JwtSignOptions = {
            secret: process.env.JWT_SECRET,
            expiresIn: '2w'
        };
        const accessToken = await this.jwtService.sign(payload, options);
        return { accessToken };
    }
}

userDecorator.ts

import { createParamDecorator, ExecutionContext } from "@nestjs/common";
import { User } from "./user.entity";

export const GetUser = createParamDecorator( (data, ctx: ExecutionContext): User => {
    const req = ctx.switchToHttp().getRequest();
    return req.user;
});

Any help will be greatly appreciated! Thanks

1

There are 1 answers

0
Xwebyna On

If the token is valid, decode the token and add the user payload to the request object in the canActivate method before sending true or false. The GetUser decorator gets the user object from the request.

Example:

// AuthGuard.ts

async canActivate( context: ExecutionContext ) {

....
....

request.user = currenToken // decoded token returns payload anyway
return true
}

You don't have to return false since an Unauthorized error will be thrown if the token is invalid and the exception filter will take care of that