These are the partial NestJS code snippets I have. I am trying to implement the passport local strategy for getting the username and password. I am getting -Error: Unknown authentication strategy "local", in the controller file when using the auth guard.
AuthModule.ts
import { Module } from '#nestjs/common';
import { JwtModule } from '#nestjs/jwt';
import { PassportModule } from '#nestjs/passport';
import { UserModule } from 'src/user/user.module';
import { JwtAuthController } from './jwt-auth.controller';
import { JwtAuthService } from './jwt-auth.service';
import { JwtStrategy } from './jwt.strategy';
import { LocalStrategy } from './local.strategy';
#Module({
imports: [
UserModule,
PassportModule,
JwtModule.register({
secret: process.env.SECRETKEY,
signOptions: { expiresIn: '3600s' }
})
],
controllers: [JwtAuthController],
providers: [JwtAuthService, LocalStrategy, JwtStrategy],
exports: [JwtAuthService],
})
export class JwtAuthModule {}
local.strategy.ts
import { Strategy } from 'passport-local';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable, UnauthorizedException } from '#nestjs/common';
import { JwtAuthService } from './jwt-auth.service';
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
constructor(private authService: JwtAuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser({username, password});
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
app.controller.ts
import { Body, Controller, Get, Post, Req, UnauthorizedException, UseGuards } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
import { JwtAuthService } from './jwt-auth/jwt-auth.service';
#Controller()
export class AppController {
constructor(private readonly authService: JwtAuthService) {}
#UseGuards(AuthGuard('local'))
#Post('/auth/login')
async login(#Req() req) {
return this.authService.login(req.user)
}
}
I am getting the following error on calling /auth/login API
[Nest] 26753 - 10/31/2021, 22:08:18 ERROR [ExceptionsHandler] Unknown authentication strategy "local"
Error: Unknown authentication strategy "local"
Am I missing anything? Thanks in advance.
just add the PassportModule and LocalStrategy in app.module .it will be fixed
#Module({
imports: [PassportModule],
providers: [AuthService,LocalStrategy],
})
export class AppModule {}
Fix Bug https://github.com/nestjs/nest/issues/4646
File AUTH.ts
enter code here
import { Module } from '#nestjs/common';
import { JwtModule } from '#nestjs/jwt';
import { PassportModule } from '#nestjs/passport';
import { UserModule } from 'src/user/user.module';
import { JwtAuthController } from './jwt-auth.controller';
import { JwtAuthService } from './jwt-auth.service';
import { JwtStrategy } from './jwt.strategy';
import { LocalStrategy } from './local.strategy';
#Module({
imports: [
UserModule,
PassportModule.register({defaultStrategy:'local'}),
JwtModule.register({
secret: process.env.SECRETKEY,
signOptions: { expiresIn: '3600s' }
})
],
controllers: [JwtAuthController],
providers: [JwtAuthService, LocalStrategy, JwtStrategy],
exports: [JwtAuthService],
})
export class JwtAuthModule {}
Such an old question with no answers...
In my case I was having sort of an cyclic dependency issue. Or at least it was what it looked like. Cyclic deps can be either on nest side or even on node.js require side (on the second case we end up with empty imports).
Case 1:
#Injectable()
export class MyLocalStrategy extends PassportStrategy(PassportLocalStrategy) {
hello = 'hello'
constructor(private authService: AuthService) {
console.log('load local strategy')
}
}
#Module({
imports: [
CommonModule,
PassportModule,
JwtModule.registerAsync({
async useFactory(config: ConfigService) {
const jwtSecret = config.get('APP_KEY')
const expiresIn = config.get('AUTH_TOKEN_EXPIRED')
return {
secret: jwtSecret,
signOptions: {
expiresIn,
},
}
},
inject: [ConfigService],
}),
],
providers: [
RoleService,
JwtStrategy,
JwtService,
AuthService,
],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {
constructor(private moduleRef: ModuleRef) {}
onModuleInit() {
const moduleRef = this.moduleRef
console.log('init auth module')
const local = moduleRef.get(MyLocalStrategy)
const auth = moduleRef.get(AuthService)
console.log('my modules', { local, auth }, local?.hello)
}
}
In this case the "load local strategy" never got logged. Yet "my modules" logged an empty localStrategy instance, without my "hello" property. Weird!
I hacked a fix by moving the class instantiation to a factory provider, and by requiring the dependencies with ModuleRef. The following excerpt worked fine.
#Module({
imports: [
CommonModule,
PassportModule,
JwtModule.registerAsync({
async useFactory(config: ConfigService) {
const jwtSecret = config.get('APP_KEY')
const expiresIn = config.get('AUTH_TOKEN_EXPIRED')
return {
secret: jwtSecret,
signOptions: {
expiresIn,
},
}
},
inject: [ConfigService],
}),
],
providers: [
RoleService,
JwtStrategy,
JwtService,
AuthService,
{
provide: MyLocalStrategy,
useFactory: (moduleRef: ModuleRef) => {
const auth = moduleRef.get(AuthService)
console.log('local strat factory', { auth })
return new MyLocalStrategy(auth)
},
inject: [ModuleRef],
},
],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {
constructor(private moduleRef: ModuleRef) {}
onModuleInit() {
const moduleRef = this.moduleRef
console.log('init auth module')
const local = moduleRef.get(MyLocalStrategy)
const auth = moduleRef.get(AuthService)
console.log('local', { local, auth }, local?.hello)
}
}
I also tried factory + injecting AuthService directly (through providers array, instead of using ModuleRef). I got a null AuthService.
Probably some dependency cycle on the node.js module imports, tough neither eslint or nest wouldn't say anything.
Check to see if your auth module is being imported in your entry file. app.module.ts.
My auth-module.ts
import { Module } from '#nestjs/common';
import { PassportModule } from '#nestjs/passport';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';
#Module({
imports:[UsersModule,PassportModule],
providers: [AuthService,LocalStrategy]
})
export class AuthModule {}
My app module
import { Module } from '#nestjs/common';
import { PassportModule } from '#nestjs/passport';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';
#Module({
imports:[UsersModule,PassportModule],
providers: [AuthService,LocalStrategy]
})
export class AuthModule {}
NestJs encourages scalability and therefore organizes your code in modules.
Instead of calling JwtAuthService method in the AppController, do it in the JwtAuthController. Your code should look like this:
import { Body, Controller, Get, Post, Req, UnauthorizedException, UseGuards } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
import { JwtAuthService } from './jwt-auth.service';
#Controller('auth')
export class JwtAuthController {
constructor(private readonly authService: JwtAuthService) {}
#Post('/login')
#UseGuards(AuthGuard('local'))
async login(#Req() req) {
return req.user
}
}
Nest will then instantiate all providers in the JwtAuthModule such that it will be available in it's controller (JwtController).
You Can always optimize your code by moving AuthGuard to it own file local.guard.ts given you the possibility to do any additional business logic.
import { ExecutionContext } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
import { Request } from 'express';
export class LocalGuard extends AuthGuard('local') {}
You need to import the module that implements the authentications.
It can be inside app.module.ts or inside another module that is connected to it.
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
#Module({
imports: [UsersModule, AuthModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
There is a workaround that may clarify things better
https://docs.nestjs.com/techniques/authentication#request-scoped-strategies
I have the same issue with you. My solution is importing LocalStrategy class to module file, in which I use AuthGuard for API endpoint.
For example: in file user.controller.ts I have AuthGuard('local') in the endpoint /login with method POST
//user.controller.ts
#UseGuards(AuthGuard('local'))
#Post('login')
async login (#Request() req: any) {
return req.user;
}
In my case, I just add LocalStrategy class (I also have this class in local.strategy.ts like you) in module file:
//user.module.ts
#Module({
imports: [
...
LocalStrategy,
],
controllers: [UserController],
...
}
Conclusion, NestJs is quite complicated in importing modules, don't forget to import what you want into other modules. Good luck!
I've just started with NestJS and I'm wondering what the best way to solve this error is
Nest cannot export a provider/module that is not a part of the
currently processed module (UsersModule). Please verify whether the
exported UsersService is available in this particular context.
I am following along with the documentation here and I seem to have hit a brick wall. My app won't compile so I can't test any further. I'll add some of the files as examples.
auth.module.ts
import { Module } from '#nestjs/common';
import { UsersModule } from 'src/users/users.module';
import { AuthController } from './controllers/auth/auth.controller';
import { AuthService } from './services/auth/auth.service';
#Module({
imports: [UsersModule],
controllers: [AuthController],
providers: [AuthService],
exports: [AuthService],
})
export class AuthModule {}
users.module.ts
import { Module } from '#nestjs/common';
import { MongooseModule } from '#nestjs/mongoose';
import { UsersController } from './controllers/users/users.controller';
import { User, UserSchema } from './schemas/user.schema';
import { UsersService } from './services/users/users.service';
#Module({
imports: [
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
controllers: [UsersController],
providers: [
{
provide: 'USERS_SERVICE',
useClass: UsersService,
},
],
exports: [UsersService],
})
export class UsersModule {}
users.service.ts
import { Injectable } from '#nestjs/common';
import { InjectModel } from '#nestjs/mongoose';
import { Model } from 'mongoose';
import { CreateUserDto } from 'src/users/dto/user.dto';
import { User, UserDocument } from 'src/users/schemas/user.schema';
import { IUserService } from './user';
#Injectable()
export class UsersService implements IUserService {
constructor(#InjectModel(User.name) private userModel: Model<UserDocument>) {}
// async code for database modification
}
}
Any help would be greatly appreciated! Many thanks!
The token of UsersService provider is the string 'UsersService' (or UsersService.name) not 'USERS_SERVICE'
So just use the short-hand syntax providers: [UsersService] or the right token in provide:.
How do I Access AppModule imports from Lazy-loaded Modules ?
My Angular10 App imports AngularMaterial and NXTranslate Modules in to the AppModule.
NxTranslate calls an ApiService to get a large Lookup object of thousands of translations.
This is translated at the initial loading of the AppModule.
The App has multiple lazy-loaded routes that also need to use the AnagularMaterial and NXTranslate Modules in their features.
If I use a SharedModule to load the Modules then the ApiService is called multiple times. This is obviously not good.
It should only call the ApiService & AngularMaterial once and be available for all modules.
How do I resolve this? I am struggling.
Thanks.
Update
(sorry for the long post)
This is the NXTranslate implementation - it uses a custom class.
import { environment } from './../../../../environments/environment';
import { OSCITranslateService } from './translate.service';
import { NgModule, Injector } from '#angular/core';
import { CommonModule } from '#angular/common';
import {TranslateLoader, TranslateModule} from '#ngx-translate/core';
import {TranslateHttpLoader} from '#ngx-translate/http-loader';
import {HttpClient, HttpClientModule} from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
export class CustomLoader implements TranslateLoader {
localeResourcesUrl =
`${environment.baseUrl}${environment.apiUrl.localeResources}`;
constructor(private http: HttpClient) {}
getTranslation(lang: string): Observable<any> {
let options;
const uri = `${this.localeResourcesUrl}${options && options.key ?
'/' + options.key : ''}`;
let mapped = this.http.get(uri).pipe(
map((response: any) => {
let localeData = {};
let languageCode = response?.languageVariantCode;
response.resources.forEach(item => {
localeData[item.keyName] = item.keyValue;
});
return localeData;
})
);
return mapped;
}
}
#NgModule({
declarations: [],
imports: [
CommonModule,
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: CustomLoader,
deps: [HttpClient]
}
})
],
exports: [ TranslateModule ]
})
export class NxTranslateModule {
constructor(private http: HttpClient) {
}
}
This is the sharedRootModule that imports the AngularMaterial & NXTranslate
import { SharedModule } from './shared.module';
import { NgModule, ModuleWithProviders } from '#angular/core';
#NgModule({
})
export class SharedRootModule {
static forRoot(): ModuleWithProviders<SharedModule> {
return {
ngModule: SharedModule
};
}
}
In AppModule SharedRootModule is imported
...
#NgModule({
declarations: [
AppComponent
],
imports: [
...
SharedRootModule.forRoot()
],
exports: [
...
SharedRootModule
]
....
Are you concerned about the multiple ApiService instances you might end up with? Provide the ApiService within AppModule only, or even better, use the providedIn property right in your service's decorator so it gets injected at application level. (https://angular.io/api/core/Injectable#providedIn)
I would just use a SharedModule that exports the mentioned lazy loaded modules.
I am basically follow this tutorial with very minor modifications:link
I am using nest 6.14.2 on node 12.10.0.
When running my app I get:
> recon-backend#0.0.1 start C:\Users\e5553079\Desktop\Node_Projects\recon-backend
> nest start
[Nest] 8324 - 02/10/2020, 9:28:21 AM [NestFactory] Starting Nest application...
[Nest] 8324 - 02/10/2020, 9:28:21 AM [InstanceLoader] MongooseModule dependencies initialized +53ms
[Nest] 8324 - 02/10/2020, 9:28:21 AM [ExceptionHandler] Nest can't resolve dependencies of the ReconQueryService (?). Please make sure that the argument ReconQueryModel at index [0] is available in the AppModule context.
Potential solutions:
- If ReconQueryModel is a provider, is it part of the current AppModule?
- If ReconQueryModel is exported from a separate #Module, is that module imported within AppModule?
#Module({
imports: [ /* the Module containing ReconQueryModel */ ]
})
+2ms
Error: Nest can't resolve dependencies of the ReconQueryService (?). Please make sure that the argument ReconQueryModel at index [0] is available in the AppModule context.
My files look like this:
1. app.module.ts
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '#nestjs/mongoose';
import { ReconQueryModule } from './reconQuery/reconQuery.module';
import { ReconQueryService } from './reconQuery/reconQuery.service';
import { ReconQueryController } from './reconQuery/reconQuery.controller';
#Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/backend-app', { useNewUrlParser: true }),
ReconQueryModule
],
controllers: [AppController, ReconQueryController],
providers: [AppService, ReconQueryService],
})
export class AppModule {}
2. reconQuery.service.ts
import { Injectable } from '#nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '#nestjs/mongoose';
import { ReconQuery } from './interfaces/reconQuery.interface';
import { CreateReconQueryDTO } from './dto/create-reconQuery.dto';
#Injectable()
export class ReconQueryService {
constructor(#InjectModel('ReconQuery') private readonly reconQueryModel: Model<ReconQuery>) { }
// Fetch all queries
async getAllQueries(): Promise<ReconQuery[]> {
const queries = await this.reconQueryModel.find().exec();
return queries;
}
...
3. reconQuery.interface.ts
import { Document } from 'mongoose';
export interface ReconQuery extends Document {
readonly id: number;
readonly name: string;
readonly sql: string;
}
4. reconQuery.module.ts
import { Module } from '#nestjs/common';
import { ReconQueryController } from './reconQuery.controller';
import { ReconQueryService } from './reconQuery.service';
import { MongooseModule } from '#nestjs/mongoose';
import { ReconQuerySchema } from './schemas/reconQuery.schema';
#Module({
imports: [
MongooseModule.forFeature([{ name: 'ReconQuery', schema: ReconQuerySchema }])
],
controllers: [ReconQueryController],
providers: [ReconQueryService]
})
export class ReconQueryModule {}
I wonder why it cries about ReconQueryModel as I do not have such an entity, just a ReconQuery interface.
You have extra ReconQueryService provided in AppModule.
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '#nestjs/mongoose';
import { ReconQueryModule } from './reconQuery/reconQuery.module';
import { ReconQueryService } from './reconQuery/reconQuery.service';
import { ReconQueryController } from './reconQuery/reconQuery.controller';
#Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/backend-app', { useNewUrlParser: true }),
ReconQueryModule
],
controllers: [AppController, ReconQueryController],
providers: [AppService, ReconQueryService], // <-- this causes the error
})
export class AppModule {}
#InjectModel() is provided by calling MongooseModule.forFeature(...) on a certain #Module(). ReconQueryService in ReconQueryModule is fine because that's where you have MongooseModule.forFeature() called so #InjectModel() is provided properly. However, in AppModule, you don't have MongooseModule.forFeature() so Nest cannot resolve the #InjectModel() for ReconQueryService.
Check if you really need to use ReconQueryService in AppModule (services and controllers declared in AppModule). If you don't, then remove ReconQueryService from providers array. If you do, then go to ReconQueryModule and do the following:
import { Module } from '#nestjs/common';
import { ReconQueryController } from './reconQuery.controller';
import { ReconQueryService } from './reconQuery.service';
import { MongooseModule } from '#nestjs/mongoose';
import { ReconQuerySchema } from './schemas/reconQuery.schema';
#Module({
imports: [
MongooseModule.forFeature([{ name: 'ReconQuery', schema: ReconQuerySchema }])
],
controllers: [ReconQueryController],
providers: [ReconQueryService],
exports: [ReconQueryService] // <-- add this line
})
export class ReconQueryModule {}
exported things will be available to use outside of the module they're provided in. Just import that module somewhere else.
I have a module for routing and, since it needs to reference the components it will route to, I have to import those as well.
import { NgModule } from "#angular/core";
import { Routes, RouterModule } from "#angular/router";
import { RegisterComponent } from "./admin/register/register.component";
import { LoginComponent } from "./admin/login/login.component";
import { ErrorComponent } from "./admin/error/error.component";
const routes: Routes = [
{ path: "register", component: RegisterComponent },
{ path: "login", component: LoginComponent },
{ path: "**", component: ErrorComponent }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
The components are placed in another module - AdminModule. All future components will be placed there (or in an appropriate module of their own). I wanted to replace the three imports with a single one like this.
// import { RegisterComponent } from "./admin/register/register.component";
// import { LoginComponent } from "./admin/login/login.component";
// import { ErrorComponent } from "./admin/error/error.component";
import { RegisterComponent, LoginComponent, ErrorComponent } from "./admin/admin.module";
This doesn't work and the message says that the module Admin has no exported member with name RegisterComponent etc. So I added exports section to the decorator of the AdminModule class like this.
import { NgModule } from "#angular/core";
import { CommonModule } from "#angular/common";
import { RegisterComponent } from "./register/register.component";
import { LoginComponent } from "./login/login.component";
import { ErrorComponent } from "./error/error.component";
#NgModule({
imports: [CommonModule],
exports: [RegisterComponent, LoginComponent, ErrorComponent],
declarations: [RegisterComponent, LoginComponent, ErrorComponent]
})
export class AdminModule { }
Regrettably, the error message remains and I'm not sure how to make the components to be recognized as exportees of AdminModule. How come that neither exports section nor declaration section seems to expose them and what can I do to make it so recognizable?
You are mixing Typescript exports with Angular exports. #NgModule's exports array is designed to describe the module's public API. It does not affect how Typescript will resolve your file imports.
For this line to work like expected:
import {
RegisterComponent,
LoginComponent,
ErrorComponent
} from "./admin/admin.module";
You need to export the components from the file itself.
import { NgModule } from "#angular/core";
import { CommonModule } from "#angular/common";
import { RegisterComponent } from "./register/register.component";
import { LoginComponent } from "./login/login.component";
import { ErrorComponent } from "./error/error.component";
export { RegisterComponent } from "./register/register.component";
export { LoginComponent } from "./login/login.component";
export { ErrorComponent } from "./error/error.component";
#NgModule({
imports: [CommonModule],
exports: [RegisterComponent, LoginComponent, ErrorComponent],
declarations: [RegisterComponent, LoginComponent, ErrorComponent]
})
export class AdminModule { }
Read more about Typescript's import, export and modules in the official docs.