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.