pulint
@pulint

Как исправить ошибку «invalid code_challenge» в ВК oauth2 при получении токена?

Делаю авторизацию на сайте с помощью VK ID (Без SDK с обменом кода на бэкенде).
Первую часть авторизации с получением code и device_id прошел успешно.
Когда обращаюсь к методу https://id.vk.com/oauth2/auth, получаю ошибку :

message:
error: "invalid_request"
error_description: "invalid code_challenge"

здесь указываю url и формирую параметры:
const vk = this.configService.get('vk');
    const app = this.configService.get('app');
    const { code_verifier, code_challenge } = getVerifier();

    const url = 'https://id.vk.com/oauth2/auth';
    const params = {
      grant_type: 'authorization_code',
      code,
      device_id,
      client_id: vk.appId,
      redirect_uri: app.frontend,
      code_challenge_method: 's256',
      code_verifier,
      code_challenge,
    };

здесь делаю запрос:
import * as qs from 'qs';

    const data = await this.httpService
      .post(url, qs.stringify(params), {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
      })
      .toPromise();


так формирую code_verifier и code_challenge:
import { randomBytes, createHash } from 'crypto';
import base64url from 'base64url';

export function getVerifier() {
  const code_verifier = generateRandomString(45);
  const code_challenge = getHash(code_verifier);

  return {
    code_verifier,
    code_challenge,
  };
}

function generateRandomString(length = 32) {
  const str = randomBytes(length).toString('base64');
  return base64URLEncode(str);
}

function getHash(code_verifier: string) {
  const hash = createHash('sha256')
    .update(code_verifier)
    .digest()
    .toString('base64');
  return base64URLEncode(hash);
}

function base64URLEncode(str: string) {
  return base64url.fromBase64(str);
}

Не могу понять, где и что не правильно сделал (не считая того, что вообще занялся авторизацией)
  • Вопрос задан
  • 276 просмотров
Пригласить эксперта
Ответы на вопрос 2
@russellbakh
Не вижу параметра state (32 bytes), который генерируется на самом первом этапе. Его вроде как тоже надо передавать.
Ответ написан
Комментировать
@step1ov
 Код для создания codeVerifier на бэке:
const codeVerifier = crypto
      .randomBytes(CODE_VERIFIER_LENGTH)
      .toString('hex');
    const sha256 = crypto.createHash('sha256');
    const codeChallenge = sha256.update(codeVerifier).digest('base64url');

Далее передаем его на фронт и там обращаеамся в VK, код на фронте:
VKID.Config.init({
          app: parseInt(vk_app_id), // Идентификатор приложения.
          redirectUrl: window.location.href.split("?")[0], // Адрес для перехода после авторизации.
          state, // Произвольная строка состояния приложения.
          codeChallenge, // Верификатор в виде случайной строки. Обеспечивает защиту передаваемых данных.
          scope: VK_AUTH_SCOPE, // Список прав доступа, которые нужны приложению.
          mode: VKID.ConfigAuthMode.InNewTab, // По умолчанию авторизация открывается в новой вкладке.
        });
VKID.Auth.login();

Код авторизации по коду:
this.httpService.post<AuthResultDto>(VKID_AUTH_ENDPOINT, {
        grant_type: 'authorization_code',
        code_verifier: credentials.codeVerifier,
        redirect_uri: dto.redirectUrl,
        code: dto.code,
        client_id: dto.clientId,
        device_id: dto.deviceId,
        state: credentials.state,
      }).then((res) => {
// Сохраняем токены
})
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы