Search code examples
nestjstypeorm

Nest can't resolve dependencies of the JwtStrategy


I am a newbie in NestJs world. As far as I know, I imported everything needed in the JwtStrategy. I don't know where it went wrong. Can somebody help me with this?

As far as I referred to documetation, Whenever we want to use any entity in a module, we should import that entity in the imports field in the @Module() decorator. I did it.

jwt.strategy.ts

import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy, ExtractJwt } from "passport-jwt";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { UserEntity } from "src/entities/user.entity";
import { AuthPayload } from "src/common/dtos/user.dto";

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor(
        @InjectRepository(UserEntity)
        private userRepo: Repository<UserEntity>
    ) {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            secretOrKey: process.env.SECRETKEY
        });
    }

    async validate(payload: AuthPayload): Promise<UserEntity> {
        const { username } = payload;
        const user = this.userRepo.findOne({ where: { username: username } });
        if(!user) {
            throw new UnauthorizedException();
        }
        return user;
    }
}

auth.module.ts

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserEntity } from 'src/entities/user.entity';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [
    TypeOrmModule.forFeature([UserEntity]),
    JwtModule.register({
      secret: process.env.SECRETKEY,
    }),
    PassportModule.register({
      defaultStrategy: 'jwt'
    })
  ],
  providers: [AuthService, JwtStrategy],
  controllers: [AuthController],
  exports: [PassportModule, JwtStrategy]
})
export class AuthModule {}

user.entity.ts

import { Entity, Column, OneToMany, JoinTable, BeforeInsert } from "typeorm";
import { AbstractEntity } from "./abstract-entity.abstract";
import { IsEmail } from "class-validator";
import { Exclude, classToPlain } from "class-transformer";
import * as bcrypt from "bcryptjs";
import { CategoryEntity } from "./category.entity";
import { ArticleEntity } from "./article.entity";

@Entity('User')
export class UserEntity extends AbstractEntity {
    @Column({
        type: "varchar",
        length: 80
    })
    fullName: string;

    @Column({
        type: "varchar",
        unique: true
    })
    @IsEmail()
    email: string;

    @Column({
        type: "varchar",
        unique: true
    })
    username: string;

    @Column({
        type: "varchar"
    })
    @Exclude()
    password: string;

    @Column({
        default: null,
        nullable: true
    })
    avatar: string | null;

    @Column({
        type: "varchar",
        unique: true
    })
    phoneNumber: string;

    @Column({
        type: "boolean",
        default: false
    })
    isAdmin: boolean;

    @Column({
        type: "boolean",
        default: false
    })
    isStaff: boolean;

    @Column({
        type: "boolean",
        default: false
    })
    isEmailVerified: boolean;

    @OneToMany(type => CategoryEntity, category => category.createdBy)
    @JoinTable()
    categories: CategoryEntity[];

    @OneToMany(type => ArticleEntity, article => article.createdBy)
    @JoinTable()
    articles: ArticleEntity[];

    @BeforeInsert()
    async hashPassword() {
        this.password = await bcrypt.hash(this.password, 10);
    }

    async comparePassword(attempt: string): Promise<boolean> {
        return await bcrypt.compare(attempt, this.password);
    }

    toJSON(): any {
        return classToPlain(this);
    }
}

app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from "@nestjs/typeorm";
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
import { 
  DatabaseConnectionService
 } from "./utils/database-connection.service";
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { ArticlesModule } from './articles/articles.module';
import { HttpExceptionFilter } from './common/exception-filters/http-exception.filter';
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
import { CategoryModule } from './category/category.module';

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      useClass: DatabaseConnectionService
    }),
    AuthModule,
    UsersModule,
    ArticlesModule,
    CategoryModule,
  ],
  controllers: [AppController],
  providers: [
    // {
    //   provide: APP_INTERCEPTOR,
    //   useClass: ResponseInterceptor
    // },
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter
    },
    AppService
  ],
})
export class AppModule {}

database-connection.service.ts

import { Injectable } from "@nestjs/common";
import { TypeOrmOptionsFactory, TypeOrmModuleOptions } from "@nestjs/typeorm";
import { truncate } from "fs";

@Injectable()
export class DatabaseConnectionService implements TypeOrmOptionsFactory {
    createTypeOrmOptions(): TypeOrmModuleOptions {
        return {
            type: "mysql",
            host: process.env.HOST,
            port: parseInt(process.env.PORT),
            username: process.env.DB_USERNAME,
            password: process.env.DB_PASSWORD,
            database: process.env.DATABASE, 
            entities: [__dirname + '/**/*.entity{.ts,.js}'],
            synchronize: true,
            dropSchema: true,
            autoLoadEntities: true,
            logger: "simple-console"
        };
    }
}

The Error is as follows: enter image description here


Solution

  • Based on your error, somewhere you have JwtStrategy in your imports array. If you need the JwtStrategy you should instead import the AuthModule, as providers should only be in the providers array and should never be in imports.