I am having a hard time figuring out the NestJS and PassportJS combination when it comes to the authentication/authorization process, and I am a type of developer who does not like magic when it comes to developing.
Issue
Basically, my goal is to understand how does AuthGuard knows about the Passport Strategy being implemented in the project, it could be Local Strategy, or any other, for example JWT Strategy. I have two modules AuthModule and UserModule and this is how the AuthService looks like:
@Injectable()
export class AuthService {
constructor(private usersService: UsersService){}
async validateUser(username: string, password: string): Promise<any> {
const user = await this.usersService.findOne(username);
if (user && user.password === password) {
const {password, ...result} = user
return result
}
return null
}
}
UserService:
import { Injectable } from '@nestjs/common';
export type User = any;
@Injectable()
export class UsersService {
private readonly users = [
{
userId: 1,
username: 'John Marston',
password: 'rdr1',
},
{
userId: 2,
username: 'Arthur Morgan',
password: 'rdr2',
},
]
async findOne(username: string): Promise<User | undefined> {
return this.users.find(user => user.username === username)
}
}
Passport
After installing the packages for Passport and NestJS, I imported PassportModule and implemented the LocalStrategy and also imported that strategy as a provider inside the AuthModule
LocalStrategy:
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super()
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
@Module({
imports: [UsersModule, PassportModule],
providers: [AuthService, LocalStrategy]
})
export class AuthModule {}
Login route
import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Controller()
export class AppController {
@UseGuards(AuthGuard('local'))
@Post('login')
async login(@Request() req) {
return req.user;
}
}
I understand everything up until this part. I do also understand how we get the req.user object etc. but I do not understand how does the AuthGuard knows, that we implemented Passport Local Strategy. Does it look through the files (sorry if this is dumb to say) and finds where we imported the PassportModule and also where we implemented the LocalStrategy since that class extends the PassportStrategy class, but also important to say, imported from passport-local.
I do understand that AuthGuard is a special type of Guard, but I am not sure if I understand it properly.
CodePudding user response:
I have a rather good article on this, but to put it on StackOverflow too:
Each Strategy
from a passport-*
package has a name
property that is the name for the strategy. For passport-local
that name
is local
. For passport-jwt
, that name is 'jwt'
. This doesn't always line up one to one, but each package should document what its name for passport is. This is the name that gets passed to passport.use()
and passport.authenticate()
. passport.use
is called via some clever code in the PassportStrategy
class from @nestjs/passport
to register the strategy with passport and passport.authenticate
is called inside of the AuthGuard()
using either the global default set via the passport module's options or via the mixin's parameters, like local
in your code sample.