Issue
I am facing a weird issue. I am using env-var package for managing the environnement variables in a NestJs project.
I have also installed the @nestjs/config as per that documentation. Hence the following code:
src/app.module.ts
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: 'schema.gql',
}),
ConfigModule.forRoot(),
TypeOrmModule.forRoot(config.db),
ExerciseModule,
ProgramModule,
WorkoutModule,
AthleteModule,
AuthModule,
BiometricsModule,
DailyTaskModule,
PerformanceModule,
SessionModule,
],
})
export class AppModule {}
I replaced the hardcoded JWT secret for the env var in src/auth/jwt.strategy.ts as such:
import { ExtractJwt, Strategy } from 'passport-jwt'
import { PassportStrategy } from '@nestjs/passport'
import { Injectable } from '@nestjs/common'
import * as env from 'env-var'
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: env.get('JWT_SECRET').required().asString(),
})
}
async validate(payload: any) {
return { athleteId: payload.athleteId }
}
}
and that's working fine.
But if I use the same code in src/auth/auth.module.ts:
import { Module } from '@nestjs/common'
import { AuthResolver } from './auth.resolver'
import { AuthService } from './auth.service'
import { getRepositoryToken, TypeOrmModule } from '@nestjs/typeorm'
import { TypeOrmAthleteRepository } from '../athlete/repositories/typeorm-athlete.repository'
import { JwtModule } from '@nestjs/jwt'
import { EmailGatewayToken } from './gateways/email.gateway'
import { InMemoryEmailGateway } from './gateways/in-memory-email.gateway'
import { PassportModule } from '@nestjs/passport'
import { JwtStrategy } from './jwt.strategy'
import { APP_GUARD } from '@nestjs/core'
import { GqlAuthGuard } from './gql.auth.guard'
import { ATHLETE_REPOSITORY } from '../athlete/repositories/athlete-repository.interface'
import * as env from 'env-var'
@Module({
imports: [
TypeOrmModule.forFeature([TypeOrmAthleteRepository]),
JwtModule.register({
secret: env.get('JWT_SECRET').required().asString(),
signOptions: { expiresIn: 3600 * 24 },
}),
PassportModule,
],
providers: [
{ provide: EmailGatewayToken, useClass: InMemoryEmailGateway },
{
provide: ATHLETE_REPOSITORY,
useExisting: getRepositoryToken(TypeOrmAthleteRepository),
},
{
provide: APP_GUARD,
useClass: GqlAuthGuard,
},
JwtStrategy,
AuthResolver,
AuthService,
],
})
export class AuthModule {}
Now I can't compile the project, I face this error:
➜ back git:(feature/use-real-token-after-login) ✗ yarn start:dev
yarn run v1.22.17
$ nest start --watch
[2:01:43 PM] Starting compilation in watch mode...
[2:01:47 PM] Found 0 errors. Watching for file changes.
/Users/arthurmehmetoglu/Development/corpo-sano-2/back/node_modules/env-var/lib/variable.js:47
throw new EnvVarError(errMsg)
^
EnvVarError: env-var: "JWT_SECRET" is a required variable, but it was not set
at raiseError (/Users/arthurmehmetoglu/Development/corpo-sano-2/back/node_modules/env-var/lib/variable.js:47:11)
at Object.asString (/Users/arthurmehmetoglu/Development/corpo-sano-2/back/node_modules/env-var/lib/variable.js:64:11)
at Object.<anonymous> (/Users/arthurmehmetoglu/Development/corpo-sano-2/back/src/auth/auth.module.ts:21:48)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Module.require (node:internal/modules/cjs/loader:1005:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.<anonymous> (/Users/arthurmehmetoglu/Development/corpo-sano-2/back/src/program/program.module.ts:6:1)
What's the issue here?
Solution
It looks like env-var reads from process.env by default. Nest ends up callingdotenv's parse method and populating process.env inside of the forRoot() method, but that does not happen immediately. All code inside of decorators (including @Module()) is called at the time of file import, so what's happening here is that you're trying to access prcoess.env.JWT_SECRET before it is populated. One option would be to make the register a registerAsync and give it a dependency on the ConfigService to ensure that the process.env has been populated before trying to read env.get('JWT_SECRET').
This works inside of the constructor, by the way, because that's at a later time once Nest has populated the process.env.
Another option would be to forgo Nest's ConfigModule and add import 'dotenv/config' as the first line of your main.ts file, so that you just leave populating the process.env object to dotenv and don't use Nest's ConfigService as an injectable.
Answered By - Jay McDoniel
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.