I have already implemented the jwt authentication. The problem occurs with Github Authentication using passport-github2
in Nest JS? I keep running into the error where I get req.user
is equal to undefined
in the callback url of the github auth. Below is my code for more context:
// github.strategy.ts
import { Injectable, Logger } from '@nestjs/common';
import { AppConfig } from '@/lib/config/config.provider';
import { PassportStrategy } from '@nestjs/passport';
import {
Strategy,
Profile,
StrategyOptionsWithRequest,
} from 'passport-github2';
import { AuthenticationService } from '../authentication.service';
import { Request } from 'express';
type VerifyCallback = (error: any, user?: any, info?: any) => void;
const githubOptions: StrategyOptionsWithRequest = {
clientID: AppConfig.authentication.GITHUB_CLIENT_ID,
clientSecret: AppConfig.authentication.GITHUB_CLIENT_SECRET,
callbackURL: AppConfig.authentication.GITHUB_CALLBACK_URL,
passReqToCallback: true,
scope: ['user:email'],
};
@Injectable()
export class GithubStrategy extends PassportStrategy(Strategy, 'github') {
private readonly logger = new Logger(GithubStrategy.name);
constructor(private readonly authService: AuthenticationService) {
super(githubOptions);
}
async validate(
req: Request,
accessToken: string,
_refreshToken: string,
profile: Profile,
done: VerifyCallback,
): Promise<any> {
try {
console.log('GitHub Profile:', profile);
const user = await this.authService.validateGithubUser(profile);
console.log('User object from AuthService:', user);
if (!user) {
console.log('No user found');
return done(null, false);
}
console.log('User object passed to done callback:', user);
return done(null, user);
} catch (err) {
this.logger.error('Failed to validate github authentication', {
error: err,
});
throw new Error(err);
}
}
}
// github.guard.ts
import {
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class GithubAuthGuard extends AuthGuard('github') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
handleRequest(err, user, _info) {
if (err || !user) {
throw err || new UnauthorizedException();
}
return user;
}
}
// authentication.module.ts
import { Global, Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { JwtModule } from '@nestjs/jwt';
import { AuthenticationController } from './authentication.controller';
import { AuthenticationService } from './authentication.service';
import { LocalStrategy } from './strategies/local.strategy';
import { AccessTokenJwtStrategy } from './strategies/access-token.strategy';
import { AppEventHandler } from '@/common/events/app.events';
import { GithubStrategy } from './strategies/github.strategy';
@Global()
@Module({
imports: [
PassportModule.register({
defaultStrategy: ['jwt', 'github'],
session: false,
}),
JwtModule.register({}),
EventEmitterModule.forRoot(),
],
controllers: [AuthenticationController],
providers: [
AuthenticationService,
LocalStrategy,
AccessTokenJwtStrategy,
GithubStrategy,
AppEventHandler,
],
exports: [AuthenticationService],
})
export class AuthenticationModule {}
// auth.controller.ts
@UseGuards(GithubAuthGuard)
@Get('/auth/github')
public githubAuth() {}
@UseGuards(GithubAuthGuard)
@Get('/auth/github/callback')
public async githubAuthCallback(@Req() req: Request) {
const user = req.user;
console.log('User object in controller:', user);
if (!user) {
return { message: 'Authentication failed' };
}
return { message: 'Authentication successful', user: user };
}
In my github.strategy.ts
, I logged to user object to see if it is been found or created by the validateGithubUser
method. Yes, it is. So I am guessing the user is not been passed alongside the request. That is the problem.
I expect to get the req.user
on the githubAuthCallback
method not to be undefined at least for now