Ошибка с passport js vkontakte(nest js)

Всем привет. Я пытаюсь настроить выполнение входа через vk, для этого использую @nestjs/passport passport-vkontakte. Собственно, почти такой же функционал я уже реализовал для входа ччерез google и там все работает хорошо. Но при входе через вк, почему-то, возникает ошибка VKontakteStrategy: verify callback must take 4 or 5 parameters. Все те параметры, которые должна принимать функция она принимает. Но, кажется, VKStrategy вызывает, почему-то, не тот метод. Я открыл исходный код, где как раз и высчитавается количество аргументов, которое принимает метод, поставил там console.log(verify.length), которые выводит значение 0. Вот код моей стратегии:

import {Injectable} from "@nestjs/common";
import {PassportStrategy} from "@nestjs/passport";
import {Strategy, Profile, VerifyCallback} from "passport-vkontakte";

import {HelperService} from "../../helper/helper.service";


@Injectable()
export class VKStrategy extends PassportStrategy(Strategy, "vkontakte") {
    constructor(private helperService: HelperService) {
        super({
            clientID: process.env.VK_CLIENT_ID,
            clientSecret: process.env.VK_SECRET,
            callbackURL: process.env.VK_REDIRECT_URI,
            scope: ['profile'],
        });
    }

    async validate(accessToken: string, refreshToken: string, profile: Profile, done: VerifyCallback): Promise<any> {
        console.log('verify')
        const payload = this.helperService.createAuthPayload(profile);

        done(null, payload);
    }
}

Ответы (2 шт):

Автор решения: Alexey

я не так давно тоже столкнулся с этой проблемой - насколько я понял в пакете passport-vkontakte реализация немного отличается от остальных (могу судить по Google и Yandex, подключение которых было идентичным). В данном случае метод validate(...) не вызовется, вместо него нужно передать обработчик в конструкторе вторым аргументом после options примерно так:

constructor(private helperService: HelperService) {
    super({
        clientID: process.env.VK_CLIENT_ID,
        clientSecret: process.env.VK_SECRET,
        callbackURL: process.env.VK_REDIRECT_URI,
        scope: ['profile'],
    }, function (
       accessToken: string,
       refreshToken: string,
       params: Params,
       profile: Profile,
       done: VerifyCallback
    ) {

      // ...какая-то логика

      return done(null, {
         profile: {
           name: profile.displayName,
           // ...любые другие данные
         }
      });
    });
}

После этого данные будут доступны в в колбеке после редиректа в req.user.profile

→ Ссылка
Автор решения: Aleksey Mikhailov

Мне помог комментарий с ответом. Скину немного доработанную версию, как оставить логику через метод validate + возможность использовать заинжекченные сервисы

import { Injectable, Inject } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, Params, Profile, VerifyCallback } from 'passport-vkontakte';
import { ConfigService } from '@nestjs/config';
import { AuthService} from '../servcies/AuthService';

@Injectable()
export class VkStrategy extends PassportStrategy(Strategy, 'vk') {
  private authService: AuthService; // Объявляем свойство с сервисом

  constructor(
    private readonly configService: ConfigService,
    @Inject(AuthService) authService: AuthService, // инжектим сервис
  ) {
    super({
      clientID: configService.get<string>('VK_CLIENT_ID'),
      clientSecret: configService.get<string>('VK_CLIENT_SECRET'),
      callbackURL: configService.get<string>('SERVER_HOST') + '/api/auth/vk/callback',
      scope: ['email'],
      profileFields: ['id', 'displayName'],
    }, 
    // Явно задаём функцию обработчик
    async (
      accessToken: string, refreshToken: string, params: Params,
      profile: Profile, done: VerifyCallback) => {
        return this.validate(
          accessToken, refreshToken, params, profile, done);
    });
    this.authService = authService; // Передаём сервис в свойство
  }

  async validate(
    accessToken: string,
    refreshToken: string,
    params: Params,
    profile: Profile,
    done: VerifyCallback,
  ) {
    const { id, displayName } = profile;

    // Используем подключённый сервис
    const user = await this.authService.validateOauthUser(displayName, id);
    return done(null, user);
  }
}
→ Ссылка