Search code examples
nestjskeycloaknestjs-config

Configure Keycloak Adapter in NestJs Backend with Custom Config Service


I have a NestJS Backend. My AmcConfigService wraps the nestjs ConfigService and is part of a AmcServerUtilsModule that includes things that all of my backends need. I want to include the call to the KeycloakConnectModule (nest-keycloak-connect) into this shared module as well. The backends shall do their config via .env file.


The logged error when I start the backend:

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

I import the shared Module in the AppModule of each Backend

@Module({
    imports: [ AmcServerUtilsModule,... ] 
})
export class AppModule { }

The shared module

@Module({
    imports: [
        ConfigModule.forRoot({
            expandVariables: true,
            isGlobal: true
        }),
        KeycloakConnectModule.registerAsync({
            inject: [AmcConfigService],
            useFactory: async (config: AmcConfigService) => ({
                authServerUrl:  config.get("AMC_KEYCLOAK_URL"),
                realm:          config.get("AMC_KEYCLOAK_REALM"),
                clientId:       config.get("AMC_KEYCLOAK_CLIENTID"),
                secret:         config.get("AMC_KEYCLOAK_SECRET"),
            })
          })
    ],
    controllers: [],
    providers: [AmcConfigService, MailService],
    exports: [AmcConfigService, MailService]

})
export class AmcServerUtilsModule {}

I have already tried different things and found some similar problems in the web and tried their solutions but it seems like I change things in the wrong place.

I need help to find my mistake.


Solution

  • Seems like the AmcConfigService was not available for the imports. I built an own Module that provides and exports the AmcConfigService and imported that module in front of the import of the KeycloakConnectModule. Now it works.

    @Module({
        imports: [
            AmcConfigModule,
            KeycloakConnectModule.registerAsync({
                imports: [AmcServerUtilsModule],
                inject: [AmcConfigService],
                useFactory: async (config: AmcConfigService) => {
                    ...
                }
              }),
            
        ],
        ...    
    })
    export class AmcServerUtilsModule {}
    

    @Module({
        imports: [
            ConfigModule.forRoot({
                expandVariables: true,
            }),
        ],
        controllers: [],
        providers: [AmcConfigService],
        exports: [AmcConfigService]
    
    })
    export class AmcConfigModule { }