Reputation: 11
I am a new coder with nestjs, I want to use passport-jwt , nestjs/passport and firebase to build my app's authetication part, below are my codes. But I just got http 401 response, how can i fix it ?
here is my strategy:
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { getAuth } from 'firebase-admin/auth';
@Injectable()
export class FirebaseStrategy extends PassportStrategy(Strategy, 'firebase') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKeyProvider: async (request, rawJwtToken, done) => {
try {
const decodedToken = await getAuth().verifyIdToken(rawJwtToken);
done(null, decodedToken);
} catch (error) {
done(error);
}
},
});
}
async validate(payload: any) {
console.log('validate');
return payload;
}
}
here is my guard:
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class FirebaseAuthGuard extends AuthGuard('firebase') {}
here is my auth.module.ts:
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { FirebaseStrategy } from './firebase.stragety';
import { AuthController } from './auth.controller';
@Module({
controllers: [AuthController],
imports: [UsersModule, PassportModule, JwtModule.register({})],
providers: [AuthService, FirebaseStrategy],
exports: [AuthService],
})
export class AuthModule {}
and here is my controller:
import { Controller, Get, Request, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { FirebaseAuthGuard } from './firebase.guard';
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
@UseGuards(FirebaseAuthGuard)
@Get('login')
async logIn(@Request() req) {
return 'login';
}
}
I just found my validate method in FirebaseStrategy not invoked, it should be invoked everytime when secretOrKeyProvider verified jwt in http header, isn't it ?
Upvotes: 1
Views: 2023
Reputation: 63
The callback definition secretOrKeyProvider
is used to return the secret that is required to verify the JWT. It is not intended to verify the JWT in this callback, see also here: https://www.passportjs.org/packages/passport-jwt/
The validation of the JWT should be done an a validate function, so move your await getAuth().verifyIdToken(rawJwtToken);
into a validate function. I use it normally like this:
async validate(payload: any) {
console.log('validate');
let user;
if (payload) {
this.logger.debug('Received a normal access token, check access token.');
user = await this.usersService.validateJwtPayload(payload);
}
if (!user) {
throw new UnauthorizedError();
}
return user;
}
In the validateJwtPayload I e.g. lookup the user and ensure the user was not deativated in the meantime, save a lastSeenAt timestamp for the user in the database. If the user is inactivated or payload.username does not exist return there undefined which will then block access.
Upvotes: 1
Reputation: 70510
If you're getting a 401 with no call of the validate
method of your JwtStrategy
that means that for some reason passport is reading the JWT
you send as invalid. To find the specific reason for it you can modify your FirebaseAuthGuard
to have the following handleRequest
method, which will log out extra details
handleRequest(err, user, info, context, status) {
console.log({ err, user, info, context, status });
return super.handleRequest(err, user, info, context, status);
}
As mentioned, this will print out what error or info passport is reading and throwing for, and will allow you to properly adjust your JWT/know to refresh it/change it because of invalid signature/whatever else.
Upvotes: 1