Nestjs: secretOrPrivateKey must have a value

대현·2021년 12월 10일
8

nestjs-question-record

목록 보기
2/2

nest는 ConfigModule을 통해서 .env에 접근할 수 있는 기능을 제공한다. 그래서 보통 app.module.ts에 처음부터 import 해두는데 i/o를 불러오는 작업이 async해서 꼭 import한 순서대로 진행되지 않는다. 즉, 내가 process.env를 사용하려던 시점에 .env를 완전히 읽지 못해서 undefined가 오는 경우도 있을 수 있다는 것이다.

최근에 로그인 기능을 구현하면서 jwt 토큰을 발행할 일이 있었는데 JwtModule에 secret을 등록하기 위해 아래와 같이 process.env.JWT_SECRET을 입력해뒀다.

@Module({
  imports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
    PassportModule.register({
      defaultStrategy: 'jwt',
      session: false,
    }),
    JwtModule.register({
      secret: process.env.JWT_SECRET,
      signOptions: { expiresIn: '1d' },
    }),
  ],
  controllers: [UsersController],
  providers: [UsersService, UsersRepository],
})
export class UsersModule {}

앞서 설명했다시피 .env를 읽어오는 작업은 비동기적이다. 이로 인해 JwtModule.register에서 process.env.JWT_SECRET을 참조할 때까지 .env를 다 못 읽어오는 일이 발생했다. 그래서 Error: secretOrPrivateKey must have a value라는 에러가 발생했지만 다행히도 이에 대한 해답을 stackoverflow에서 찾아냈다.

JwtModule에는 registerAsync라는 메소드가 있는데 여기에 ConfigService를 주입해두면 .env를 읽어올 때까지 secret을 등록하는 작업을 유예시킬 수 있다.

import { ConfigService } from '@nestjs/config';
@Module({
  imports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
    PassportModule.register({
      defaultStrategy: 'jwt',
      session: false,
    }),
    JwtModule.registerAsync({
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        secret: config.get<string>('JWT_SECRET'),
        signOptions: { expiresIn: '1d' },
      }),
    }),
  ],
  controllers: [UsersController],
  providers: [UsersService, UsersRepository],
})
export class UsersModule {}

추가로, ConfigModule.forRoot({ isGlobal: true })처럼 isGlobal 옵션을 true로 바꿔주면 정상적으로 작동한다.

다른 모듈을 등록할 때도 비슷한 문제가 발생할 수 있으니 위의 사례를 참조해서 진행하자.
isGlobal을 true로 했는데 뭐가 문제지?
ConfigService 사용했는데 뭐가 문제지?

profile
백일까 프론트일까

1개의 댓글

comment-user-thumbnail
2022년 5월 9일

감사합니다 !!

답글 달기