Lokicoule / nestjs-cognito

AWS Cognito utilities module for NestJS.
https://www.npmjs.com/package/@nestjs-cognito/auth
MIT License
81 stars 7 forks source link

Nest can't resolve dependencies of the Service (ConfigService, ?). Please make sure that the argument COGNITO_IDENTITY_PROVIDER_INSTANCE_TOKEN at index [1] is available in the Module context. #808

Closed mikhin closed 10 months ago

mikhin commented 10 months ago

I have the following code:

@Module({
  imports: [
    ConfigModule.forRoot({
      cache: true,
      isGlobal: true,
      load: [appConfig],
    }),
    CognitoModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService<ApplicationConfig>) => {
        const cognitoClientID = configService.get('cognitoClientID');
        const cognitoMainRegion = configService.get('cognitoMainRegion');
        const cognitoUserPoolID = configService.get(
          'cognitoUserPoolID',
        ) as string;

        return {
          identityProvider: {
            region: cognitoMainRegion,
          },
          jwtVerifier: {
            clientId: cognitoClientID,
            tokenUse: 'id',
            userPoolId: cognitoUserPoolID,
          },
        };
      },
    }),
   Module,
  ],
})
export class AppModule {}
import {
  CognitoIdentityProvider,
  ListUsersInGroupCommandOutput,
} from '@aws-sdk/client-cognito-identity-provider';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { InjectCognitoIdentityProvider } from '@nestjs-cognito/core';
import { ApplicationConfig } from '../app.config';

@Injectable()
export class Service {
  constructor(
    private configService: ConfigService<ApplicationConfig>,
    @InjectCognitoIdentityProvider()
    private readonly client: CognitoIdentityProvider,
  ) {}

  getList(): Promise<ListUsersInGroupCommandOutput> {
    const poolId = this.configService.get('cognitoUserPoolID');
    const GroupName = this.configService.get('cognitoGroupName');

    console.log(this.client);

    return this.client.listUsersInGroup({
      GroupName: GroupName,
      UserPoolId: poolId,
    });
  }
}

and I have the error:

[Nest] 11596  - 01/08/2024, 4:16:31 PM   ERROR [ExceptionHandler] Nest can't resolve dependencies of the Service (?, ConfigService). Please make sure that the argument COGNITO_IDENTITY_PROVIDER_INSTANCE_TOKEN at index [0] is available in the Module context.

Potential solutions:
- Is Module a valid NestJS module?
- If COGNITO_IDENTITY_PROVIDER_INSTANCE_TOKEN is a provider, is it part of the current Module?
- If COGNITO_IDENTITY_PROVIDER_INSTANCE_TOKEN is exported from a separate @Module, is that module imported within Module?
  @Module({
    imports: [ /* the Module containing COGNITO_IDENTITY_PROVIDER_INSTANCE_TOKEN */ ]
  })

How can i fix it?

Lokicoule commented 10 months ago

Hello @mikhin,

Can you please provide the module definition where you are injecting your Service?

mikhin commented 10 months ago

@Lokicoule , thanks for the fast response!

import { Module } from '@nestjs/common';
import { AdminsController } from './admins.controller';
import { AdminsService } from './admins.service';

@Module({
  controllers: [AdminsController],
  providers: [AdminsService],
})
export class AdminsModule {}
Lokicoule commented 10 months ago

Thanks!

And where are you importing this AdminsModule? Because based on the AppModule you are not importing it anywhere so DI containers are not shared between these 2 modules.

mikhin commented 10 months ago

Sorry, for misspelling, it imported as Module in AppModule.

Lokicoule commented 10 months ago

I guess it's missing an import inside AdminsModule.

From my experience, it's better to have an atomic approach for managing module composition.

If you extract cognito registering logic to a new module let's call it CognitoModule and import this module inside your AdminsModule does it work?

For example only: (@nestjs-cognito version is outdated here so the DX is not the same) https://github.com/Lokicoule/nestjs-graphql-boilerplate/blob/main/apps/users-application/src/cognito/cognito.provider.module.ts https://github.com/Lokicoule/nestjs-graphql-boilerplate/blob/main/apps/users-application/src/users/presentation/users-presentation.module.ts

mikhin commented 10 months ago

Thank you!

I thought it was supposed to work globally if I import into an AppModule?

At least that's how it works with CognitoAuthModule - I do registerAsync in AppModule and then use Authorization, CognitoUser decorators in different modules, without additional imports within those modules.

Lokicoule commented 10 months ago

It's a very good point and I forgot about it, but it's as simple as that:

This design decision was made to simplify imports when using the auth package as the API entry point while enforcing specific importation requirements when using the core package. In your initial code, instead of using CognitoModule, go for AuthCognitoModule. It essentially acts as a convenient adapter for CognitoModule, and it should work seamlessly.

mikhin commented 10 months ago

Thanks for clarifications and fast answers! Really appreciated!