Search code examples
javascriptjwtnestjs

Can't access env file with jwt constants.ts


I have a project and I need to implement JWT service. I have followed the nest.js docs for this. In the file constants.ts I export an object that has a secret for key and my process.env for value

export const jwtConstants = () => ({
  secret: process.env.SECRET_JWT,
});

and this doesn't work. I have tried with a key directly in value and that works. I don't know why I can't access my env file in this file. This is my auth module:

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UserService } from '../user/user.service';
import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from '../user/user.schema';
import { JwtModule } from '@nestjs/jwt';
import { jwtConstants } from './constants';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
    JwtModule.register({
      global: true,
      secret: jwtConstants.secret,
      signOptions: { expiresIn: '60s' },
    }),
  ],
  providers: [AuthService, UserService],
  controllers: [AuthController],
})
export class AuthModule {}

my auth service

import { Injectable } from '@nestjs/common';
import { UserService } from '../user/user.service';
import { AuthDto } from './dto/auth.dto';
import { JwtService } from '@nestjs/jwt';
import * as argon2 from 'argon2';

@Injectable()
export class AuthService {
  constructor(
    private userService: UserService,
    private jwtService: JwtService,
  ) {}

  async signIn(authDto: AuthDto): Promise<{ access_token: string }> {
    const user = await this.userService.findOne(authDto.email);
    try {
      if (await argon2.verify(user.password, authDto.password)) {
        const payload = {
          userName: user.firstName,
          userLastName: user.lastName,
          userPhone: user.phone,
          userEmail: user.email,
        };
        return {
          access_token: await this.jwtService.signAsync(payload),
        };
      } else {
        console.log('doesn\t match');
      }
    } catch (error: any) {
      console.log('doesn\t work');
    }
  }
}

and my app module with the ConfigModule.forRoot

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule } from '@nestjs/config';
import { UserModule } from './user/user.module';
import { CompanyModule } from './company/company.module';
import { CallForBidsModule } from './callForBids/call-for-bids.module';
import { AuthModule } from './auth/auth.module';
import { User, UserSchema } from './user/user.schema';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: '.env',
    }),
    MongooseModule.forRoot(process.env.MONGO_DB_URL, {
      dbName: process.env.MONGO_DB_DATABASE_NAME,
      auth: {
        username: process.env.MONGO_DB_USERNAME,
        password: process.env.MONGO_DB_PASSWORD,
      },
    }),
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
    // feature module
    UserModule,
    CompanyModule,
    CallForBidsModule,
    AuthModule,
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

I have tried changing the lib and added the dotenv lib for Nestjs but got the same result. I have tried with the key directly that worked but I need to use the .envfile Rebuild the project doesn't work either.


Solution

  • With your current jwtConstants you should be accessing the secret like jwtConstants().secret as it's a function export.

    However, as you're using @nestjs/config, the better approach would be to use JwtModule.registerAsync and inject the ConfigService to the JwtModule rather than relying on process.env, so ensure that the values are coming from where you think they are. This would look something like

    import { Module } from '@nestjs/common';
    import { AuthService } from './auth.service';
    import { AuthController } from './auth.controller';
    import { UserService } from '../user/user.service';
    import { MongooseModule } from '@nestjs/mongoose';
    import { User, UserSchema } from '../user/user.schema';
    import { JwtModule } from '@nestjs/jwt';
    import { jwtConstants } from './constants';
    
    @Module({
      imports: [
        MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
        JwtModule.registerAsync(
          inject: [ConfigService],
          useFactory: (config: ConfigService) => ({
            global: true,
            secret: config.get('SECRET_JWT'),
            signOptions: { expiresIn: '60s' },
          }),
        }),
      ],
      providers: [AuthService, UserService],
      controllers: [AuthController],
    })
    export class AuthModule {}
    

    You can also do a similar approach with your MongooseModule using a forRootAsync to inject the ConfigService and get the env variables from there