Nestjs Passport google Oauth2 with custom JWT

984 Views Asked by At

What I need to achieve -

  1. I need to have a dynamic redirect URL (not google's refer Current Flow last step) based on the query param sent by Frontend.
  2. I need to send my custom JWT token instead of google token which can have roles and permission in it. (Not sure if we can add claims to google token as well)
  3. In my app, I have 2 roles - candidate, and recruiter. I need to use Gmail auth and create a user in my DB according to roles, which again I could achieve via query param pass by Frontend.

Current Flow -

Frontend calls google/login -> GoogleAuthGaurd -> GoogleStrategy -> google/redirect -> Generate custom JWT token -> redirect to frontend with access token and refresh token in URL.

Problem -

In Passport, we have GoogleAuthGaurd, and GoogleStrategy. I have read somewhere that Auth Gaurd decides which strategy to be used and it internally calls the strategy and further execution.

If I pass query param to google/login it totally ignores it and redirects to strategy. We can access contecxt (ExecutionContext) in AuthGaurd, so we can get query param there but how to pass it to strategy? or may be invoke custom strategy from auth guard not sure if we can.

Is there any way I could pass the query param to strategy then I could write a logic to update the redirect URI or roles?

import { TokenResponsePayload } from '@identity/payloads/responses/token-response.payload';
import { Controller, Get, Inject, Req, Res, UseGuards } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Request, Response } from 'express';
import {
  AuthServiceInterface,
  AuthServiceSymbol,
} from '../interfaces/services/auth-service.interface';
import { AccessTokenGaurd } from '../utils/access-token.guard';
import { GoogleAuthGaurd } from '../utils/google-auth-guard';
import { RefreshTokenGuard } from '../utils/refresh-token.guard';

@ApiTags('Auth')
@Controller('auth')
export class AuthController {
  constructor(
    @Inject(AuthServiceSymbol)
    private authService: AuthServiceInterface,
  ) {}

  @Get('google/login')
  @UseGuards(GoogleAuthGaurd)
  handleGoogleLogin() {}

  @Get('google/redirect')
  @UseGuards(GoogleAuthGaurd)
  async handleGoogleRedirect(@Req() req, @Res() res: Response) {
    const tokens = await this.authService.signInWithGoogle(req);
    res.redirect(302,`http://127.0.0.1:4200?access_token=${tokens.accessToken}&refresh_token=${tokens.refreshToken}`)
  }

  @Get('logout')
  @UseGuards(AccessTokenGaurd)
  async remove(@Req() req: Request): Promise<void> {
    return this.authService.removeSession(req.user['sessionId']);
  }

  @UseGuards(RefreshTokenGuard)
  @Get('refresh')
  async refreshToken(@Req() req: Request): Promise<TokenResponsePayload> {
    const sessionId = req.user['sessionId'];
    const refreshToken = req.user['refreshToken'];
    return this.authService.refreshTokens(sessionId, refreshToken);
  }
}
import { Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport';

@Injectable() export class GoogleAuthGaurd extends AuthGuard('google') {}


import { CalConfigService, ConfigEnum } from '@cawstudios/calibrate.common';
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Profile, Strategy } from 'passport-google-oauth20';
import { VerifiedCallback } from 'passport-jwt';

const configService = new CalConfigService();
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      clientID: configService.get(ConfigEnum.CLIENT_ID),
      clientSecret: configService.get(ConfigEnum.CLIENT_SECRET),
      callbackURL: configService.get('CALLBACK_URL'),
      scope: ['profile', 'email'],
    });
  }
  async validate(
    accessToken: string,
    refreshToken: string,
    profile: Profile,
    done: VerifiedCallback,
  ): Promise<any> {
    const email = profile.emails[0].value;
    done(null, email);
  }
}
0

There are 0 best solutions below