@nestjs - JwtModule.registerAsync is failing to register in a timely manner, resulting in unresolved dependencies

Encountering some challenges with the registerAsync function in combination with JwtModule and JwtService. While browsing various discussions, it seems like many were stuck on ConfigModule, but that's not a part of my project.

Let me provide some context:

// secret-key.helper.ts

/*
  Retrieve the JWT secret value from AWS Secrets Manager. This is used to
  sign JWTs. Imports are already included.
*/
async function retrieveJwtSecret(): Promise<string> {
  const secretClient = new SecretsManagerClient({
    region: process.env.AWS_REGION,
  });
  const getSecretCom = new GetSecretValueCommand({
    SecretId: process.env.JWT_SECRET_ARN,
  });
  const jwtSecret = (await secretClient.send(getSecretCom)).SecretString;
  return jwtSecret;
}
// auth.module.ts

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtModule } from '@nestjs/jwt';
import { retrieveJwtSecret } from '../../utils/secret-key.helper';

@Module({
  imports: [
    JwtModule.registerAsync({
      useFactory: async () => ({
        global: true,
        secret: await retrieveJwtSecret(),
        signOptions: { expiresIn: '16h' },
      }),
    }),
  ],
  controllers: [AuthController],
  providers: [AuthService],
})
export class AuthModule {}
// my.guard.ts

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Request } from 'express';
import { logEvent } from '../log-event.helper';
import { JwtService } from '@nestjs/jwt';
import { JwtPayloadDto } from 'src/models/auth/dto/jwt-payload.dto';

@Injectable()
export class MyGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}
  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const req = context.switchToHttp().getRequest();

    /* JWT Authentication */
    const token = this.extractTokenFromHeader(req);
    if (!token) {
      logEvent('ERROR: No token found.', req.headers);
      return false;
    } else {
      const payload = this.jwtService.decode(token) as JwtPayloadDto;
      logEvent('Token found.', payload);
      return true;
    }
  }
}

The first snippet demonstrates how I fetch the JWT secret key from AWS Secrets Manager. The second code block showcases the auth module with the usage of retrieveJwtSecret() method within the registerAsync global import (which is causing issues). The third block is regarding the guard being utilized.

When Nest encounters the imported Guard in the first module, it throws a "can't resolve dependencies" error. Switching from registerAsync to register, manually extracting the secret key in

main.ts</code, and assigning it to <code>process.env
resolves the issue.

The specific error message reads:

ERROR [ExceptionHandler] Nest can't resolve dependencies of the MyGuard (?).
Please make sure that the argument JwtService at index [0] is available in the BenefitsModule context.

Potential solutions: ...

By utilizing console.log, it was determined that the execution initiates in the retrieveJwtSecret function and has access to the necessary .env variables during runtime. However, the process never completes the

const jwtSecret = await secretClient.send...
call. It is speculated that Nest continues loading modules requiring JwtModule before obtaining the secret and finalizing the setup of JwtModule.

If feasible, I prefer avoiding the implementation of register as previously mentioned. Is there a way to compel Nest to await async dependencies?

Thank you!

Answer №1

It is important to note that the `global` option of `JwtModule.registerAsync` should be on the same level as `useFactory`, rather than being a part of the options returned by the `useFactory`. To ensure correct module setup, your module structure should resemble the following:

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtModule } from '@nestjs/jwt';
import { retrieveJwtSecret } from '../../utils/secret-key.helper';

@Module({
  imports: [
    JwtModule.registerAsync({
      global: true,
      useFactory: async () => ({
        secret: await retrieveJwtSecret(),
        signOptions: { expiresIn: '16h' },
      }),
    }),
  ],
  controllers: [AuthController],
  providers: [AuthService],
})
export class AuthModule {}

This adjustment will truly make the `JwtModule` globally accessible.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Showing data from a Node.js Express application in a Jade template file

I am encountering an issue with my simple jade page where not all variables passed from the javascript route are displaying correctly. I have attempted to implement the solution described in this answer, but it seems to be ineffective in my case. My goal i ...

What improvements can I make to enhance my method?

I have a block of code that I'm looking to clean up and streamline for better efficiency. My main goal is to remove the multiple return statements within the method. Any suggestions on how I might refactor this code? Are there any design patterns th ...

Guide on running a MySQL query in an asynchronous function in a Node.js application

Encountering some challenges while using MySQL in a node/express JS application. It seems that when trying to access the MySQL database within an asynchronous function, the code will 'skip over' the SQL query and run synchronously. This is the co ...

ExpressJS - Error Handler Fails to Catch Any Errors

I am facing an issue with my error handler as shown below: export const errorHandler = ( error: Error, req: Request, res: Response, next: (error: Error) => void, ) => { console.log("TEST"); next(error); } Although ...

Encountering issues with deploying an Angular 8 website using a specific configuration

My current project is built on Angular 8, and I am in the process of publishing it locally before deploying it. When running the build step, I specify an environment name called internalprod: src ├───app ├───environments │ environme ...

What is the best way to send information to another client (user) using socket.io?

I am facing an issue where data is only being appended to the sender's message body instead of all connected clients. I need it to work for every user who is currently connected. After going through the documentation, it suggests that broadcasting co ...

The MessageError: expressjs is unable to read the property "image" because it is null

I am currently working on developing a shopping cart using express and mongodb. However, I encountered an error when attempting to include an image category in the form. Here is the code snippet for handling post requests in admin_product.js: router.post(& ...

Subtracted TypeScript concept

Is it possible to create a modified type in Typescript for React components? import {Component, ComponentType} from 'react'; export function connect<S, A>(state: () => S, actions: A){ return function createConnected<P>(componen ...

What advantages can be found in using various CRUD techniques?

When working with CRUD operations, the process can be done using a form like this: <form action="/todo/<%= todos[i]._id %>?_method=DELETE" method="POST> <button>x</button> </form> The corresponding con ...

Starting a fresh Angular project yields a series of NPM warnings, notably one that mentions skipping an optional dependency with the message: "npm

Upon creating a new Angular project, I encounter warning messages from NPM: npm WARN optional SKIPPING OPTIONAL DEPENDENCY: <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="68e01b0d1e0d061c7518d7">[email protecte ...

Typescript - Specifying the return type for a deeply nested object

I have a container that holds multiple sub-containers, each containing key-value pairs where the value is a URL. I also have a function that takes the name of one of the sub-containers as input, loops through its entries, fetches data from the URLs, and re ...

Building a Next.js application that supports both Javascript and Typescript

I currently have a Next.js app that is written in Javascript, but I am looking to transition to writing new code in Typescript. To add Typescript to my project, I tried creating a tsconfig.json file at the project root and then ran npm install --save-dev ...

Accessing Webpack bundles using an "@" symbol for imports

I am currently working on bundling a Node Express server that was created using TypeScript and is being packaged with Webpack. Everything seems to be running smoothly when I compile/transpile the code into one JavaScript file called server.js. However, af ...

express-validator, no validation errors have been found so far

How can I verify if a given string is in the format of an email address? Here's a snippet of code that attempts to do so: req.checkBody('email', 'Invalid email address').isEmail(); var validationErrors = req.validationErrors(); i ...

Error encountered: PM2: application unreachable due to (ERR_CONNECTION_REFUSED)

I have successfully deployed my Express.js app on Node.js. Now, I am looking to finalize the deployment with pm2. To achieve this, I have created an ecosystem.json file: { "apps": [ { "env": { & ...

Stringified HTML code showcased

When working with Angular, I have encountered an issue where I am calling a function inside an .html file that returns a string containing a table element. My goal is to convert this string into HTML code. I attempted to use [innerHtml]: <p [innerHtml ...

An optional field has been identified as ng-invalid

In my set-up, I have created a form group using reactive forms. this.transactionForm = fb.group ({ 'location': [null, Validators.required], 'shopper': [null], 'giftMessage': [null], 'retailPrice& ...

Utilizing Eithers to effectively manage errors as they propagate through the call chain

I'm delving into functional programming and exploring different ways to handle errors beyond the traditional try/catch method. One concept that has caught my attention is the Either monad in various programming languages. I've been experimenting ...

The factory class is responsible for generating objects without specifying their type

I manage a factory that specializes in facilitating dependency injection. Here's an example of what it looks like: import SomeImportantObject from "./SomeImportantObject" import DataInterface from "./DataInterface" class NoodleFactory { this.depen ...

Ways to obtain a referrer URL in Angular 4

Seeking a way to obtain the referrer URL in Angular 4. For instance, if my Angular website is example.com and it is visited from another PHP page like domaintwo.com/checkout.php, how can I detect the referring URL (domaintwo.com/checkout.php) on my Angul ...