Search code examples
oauth-2.0oauthnestjsgoogle-oauthpassport.js

Cannot destructure property 'name' of 'profile' as it is undefined. Google Passport nestjs


I'm trying so hard to implement Google Oauth with passport on NestJs. Here is what I have:

Google Strategy:

config();

@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
  constructor(private readonly authService: AuthService) {
    super({
      clientID: process.env.GOOGLE_CLIENT,
      clientSecret: process.env.GOOGLE_SECRET,
      callbackURL: process.env.GOOGLE_REDIRECT,
      passReqToCallback: true,
      scope: ['email', 'profile'],
    });
  }

  async validate(
    accessToken: string,
    refreshToken: string,
    profile: any,
    done: VerifyCallback,
  ): Promise<any> {
    console.log(profile);
    const { name, emails, photos } = profile;
    console.log(profile);
    const user = {
      email: emails[0].value,
      firstName: name.givenName,
      lastName: name.familyName,
      picture: photos[0].value,
      accessToken,
    };
    console.log(user);
    done(null, user);
  }
}

Auth controller:

@Get('google')
  @Public()
  @UseGuards(AuthGuard('google'))
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  async googleAuth(@Req() req) {}

  @Get('redirect')
  @Public()
  @UseGuards(AuthGuard('google'))
  googleAuthRedirect(@Req() req) {
    console.log('callback');
    //return this.appService.googleLogin(req);
  }

And app module:

@Module({
  imports: [
    ConfigModule.forRoot(),
    EventEmitterModule.forRoot(), // Importez le module ConfigModule
    TypeOrmModule.forRootAsync({
      useFactory: () => ({
        type: isTestEnv ? 'sqlite' : 'mysql',
        host: isTestEnv ? ':memory:' : process.env.DB_HOST,
        port: isTestEnv ? 0 : +process.env.DB_PORT,
        username: isTestEnv ? '' : process.env.DB_USERNAME,
        password: isTestEnv ? '' : process.env.DB_PASSWORD,
        database: isTestEnv ? '' : process.env.DB_DATABASE,
        autoLoadEntities: true,
        synchronize: true,
      }),
    }),
    AuthModule,
    UsersModule,
    RolesModule,
    BoatsModule,
    BoatsMembersModule,
    BoatFacadeModule,
  ],
  controllers: [AppController],
  providers: [
    AppService,

    {
      provide: APP_PIPE,
      useClass: ValidationPipe,
    },
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
    {
      provide: APP_GUARD,
      useClass: JwtAuthGuard,
    },
    {
      provide: APP_GUARD,
      useClass: RolesGuard,
    },
  ],
})
export class AppModule {}

When I start my app and goes to localhost:8000/api/auth/google, I've a sign in with Google, and when I click and sign in, I then have a 500 repsonse, and in my console: undefined [Nest] 17527 - 16/08/2023 17:47:12 ERROR [ExceptionsHandler] Cannot destructure property 'name' of 'profile' as it is undefined. TypeError: Cannot destructure property 'name' of 'profile' as it is undefined.

So console.log(profile) -> undefined and I don't know why....

Any helps ?

of course, I've setup on google.console.cloud and I've put correctly google secrets , ...

And my gmail adress is valid :)

ps: Public annotation is because I've another JwtGuards that uses a jwt strategy: my endpoint (without public annotaiton) needs to be protected with a valid access token. And it's working, I just want to use Google too.

Thanks in advance guys !! :)


Solution

  • You havepassReqToCallback: true set in the super() option of your strategy, meaning the first parameter of validate will be the request. Add that in, essentially shifting all of your parameters, and things should work out. Just double check the rest of the signature against the passport package you're using.

    Or, if you aren't using the request in the validate (which is looks like you aren't), then set that option to false and it should work as is (again, assuming the validate signature is correct)