PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Sunday, November 27, 2022

[FIXED] How to fix unknown authentication strategy "jwt" when I inject another service into user service in nestjs

 November 27, 2022     authentication, module, nestjs, node.js, passport.js     No comments   

Issue

I have a user service that handles registration, login and some other functions. I have been working on the application for sometime now with over 10 modules. But I noticed each time I injected another service and I try to consume any endpoint I get this error "Unknown authentication strategy "jwt". Error on swagger is:-

Internal Server Error
Response body

{
  "statusCode": 500,
  "message": "Internal server error"
}

Once I remove the injected service from the user module, everything is fine again. I have been trying to fix this because I need to use this service inside the user module.

This is the jwt.Strategy.ts

import { Injectable, HttpException, HttpStatus } from "@nestjs/common";
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt, VerifiedCallback } from "passport-jwt";
import { AuthService } from './auth.service';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor(private authService: AuthService) {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: false,
            secretOrKey: process.env.SECRETKEY
        });
    }

    async validate(payload: any, done: VerifiedCallback) {
        const user = await this.authService.validateUser(payload);
        try {
            if (user) {
                //return user;
                return done(null, user, payload.iat)
            } else if (user == null) {
                const Terminal = await this.authService.validatePos(payload);
                return done(null, Terminal, payload.iat)
            }
            else {
                return done(
                    //throw new UnauthorizedException();
                    new HttpException('Unauthorised access', HttpStatus.UNAUTHORIZED),
                    false,
                );
            }

        } catch (error) {
            return error;
        }
    }
}

This is the AuthModule

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UserService } from '../user/user.service';
import { UserSchema } from '../user/user.schema';
import { MongooseModule } from '@nestjs/mongoose';
import { JwtStrategy } from './jwt.strategy';
import { ActivityLogService } from '../activity-log/activity-log.service';
import { ApiKeyStrategy } from './apiKey.strategy';
import { PassportModule } from "@nestjs/passport";

@Module({
    imports: [MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
    PassportModule.register({
        secret: "mysec"
    }),
        ActivityLogService],
    providers: [AuthService, UserService, JwtStrategy, ApiKeyStrategy, ActivityLogService],
    exports: [AuthService],
    controllers: []
})
export class AuthModule { }

This is the api.strategy.ts

import { HeaderAPIKeyStrategy } from 'passport-headerapikey';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class ApiKeyStrategy extends PassportStrategy(HeaderAPIKeyStrategy) {
    constructor(private authService: AuthService) {
        super({
            header: 'api_key',
            prefix: ''
        }, true,
            (apikey: string, done: any, req: any, next: () => void) => {
                const checkKey = this.authService.validateApiKey(apikey);
                if (!checkKey) {
                    return done(
                        new HttpException('Unauthorized access, verify the token is correct', HttpStatus.UNAUTHORIZED),
                        false,
                    );
                }
                return done(null, true, next);
            });
    }
}

This is the authService


import { Injectable } from '@nestjs/common';
import { sign } from 'jsonwebtoken';
import { UserService } from '../user/user.service';
import { TerminalService } from '../terminal/terminal.service';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Terminal } from '../terminal/interfaces/terminal.interface';


@Injectable()
export class AuthService {
    constructor(private userService: UserService, @InjectModel('Terminal') private terminalModel: Model<Terminal>,) { }

    //generate token for user
    async signPayLoad(payload: any) {
        return sign(payload, process.env.SECRETKEY, { expiresIn: '1h' });
    }

    //find user with payload
    async validateUser(payload: any) {
        const returnuser = await this.userService.findByPayLoad(payload);
        return returnuser;
    }

    //generate token for Posy
    async signPosPayLoad(payload: any) {
        return sign(payload, process.env.SECRETKEY, { expiresIn: '24h' });
    }

    //find terminal with payload
    async validatePos(payload: any) {
        const { terminalId } = payload;
        const terminal = await this.terminalModel.findById(terminalId);
        return terminal;
    }

    validateApiKey(apiKey: string) {
        const keys = process.env.API_KEYS;
        const apiKeys = keys.split(',');
        return apiKeys.find(key => apiKey === key);
    }
}


This is the user service

import { Injectable, HttpException, HttpStatus, Inject } from '@nestjs/common';
import { User } from './interfaces/user.interface';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { LoginUserDto } from './login-user.dto';
import { ActivityLogService } from '../activity-log/activity-log.service';
import { UpdateUserDTO } from './dtos/update_user.dto';

@Injectable()
export class UserService {
    constructor(@InjectModel('User') private userModel: Model<User>,
        private activityLogService: ActivityLogService,
    ) { }
    
    //Login user
    private users = [
        {
            "userId": 1,
            "name": "John Doe",
            "username": "john",
            "password": "john123"
        },
    ]
    async login(loginDTO: LoginUserDto) {

        const { email, password } = loginDTO;

        return await this.users.find(users => users.username == email)
    }

    async findByPayLoad(payload: any) {
        const { userId } = payload;
        return await this.userModel.findById(userId)
    }
    async getAllUser() {
        return this.users;
    }
}

I cant figure out what I am doing wrong


Solution

Besides the code being difficult to manipulate and determine what's happening, services being in places they shouldn't and re-instantiations of services all over the place, the culprit as to why you are getting the error is simply because you never register the PassportModule from @nestjs/passport


EDIT 1/7/2017

Coming back to this answer about a year and a half later, it looks like the real issue is the use of a REQUEST scoped provider in the strategy. The nest docs explicitly mention this can't be done directly but also have a workaround for it.



Answered By - Jay McDoniel
Answer Checked By - Cary Denson (PHPFixing Admin)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing