在 ReactJS 中的 Spotify API 上为 PKCE 身份验证创建代码验证器和挑战

问题描述 投票:0回答:3

我正在尝试将 Spotify 身份验证添加到我的单页反应应用程序中 the doc from their api.

到目前为止,这是我根据在网上找到的解决方案生成代码的方式:

const generateVerifier = () => {
    return crypto.randomBytes(64).toString('hex');
}

const getChallenge = verifier => {
    return crypto.createHash('sha256')
        .update(verifier)
        .digest('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '')
}

我使用该技术创建的一对代码示例:

  • 验证者:
    e8c3745e93a9c25ce5c2653ee36f5b4fa010b4f4df8dfbad7055f4d88551dd960fb5b7602cdfa61088951eac36429862946e86d20b15250a8f0159f1ad001605
  • 挑战:
    CxF5ZvoXa6Cz6IcX3VyRHxMPRXYbv4PADxko3dwPF-I

我创建的一对旧代码的示例:

  • 验证者:
    1jp6ku6-16xxjfi-1uteidc-9gjfso-1mcc0wn-tju0lh-tr2d8k-1auq4zk
  • 挑战:
    SRvuz5GW2HhXzHs6b3O_wzJq4sWN0W2ma96QBx_Z77s

然后我收到来自 API 的响应,说“code_verifier 不正确”。我在这里做错了什么?

javascript reactjs oauth spotify pkce
3个回答
15
投票

尝试按照本指南生成代码以生成代码质询和验证器

这里是重要的部分:

生成代码验证器

// GENERATING CODE VERIFIER
function dec2hex(dec) {
  return ("0" + dec.toString(16)).substr(-2);
}

function generateCodeVerifier() {
  var array = new Uint32Array(56 / 2);
  window.crypto.getRandomValues(array);
  return Array.from(array, dec2hex).join("");
}

从代码验证器生成代码挑战

function sha256(plain) {
  // returns promise ArrayBuffer
  const encoder = new TextEncoder();
  const data = encoder.encode(plain);
  return window.crypto.subtle.digest("SHA-256", data);
}

function base64urlencode(a) {
  var str = "";
  var bytes = new Uint8Array(a);
  var len = bytes.byteLength;
  for (var i = 0; i < len; i++) {
    str += String.fromCharCode(bytes[i]);
  }
  return btoa(str)
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
}

async function generateCodeChallengeFromVerifier(v) {
  var hashed = await sha256(v);
  var base64encoded = base64urlencode(hashed);
  return base64encoded;
}

这是一个工作示例

您还可以检查代码的有效性在这里


1
投票

我从 passport oauth2 库中获取了这个片段来生成代码验证器和代码挑战。

const code_verifier = base64url(crypto.pseudoRandomBytes(32));

const code_challenge = crypto
     .createHash("sha256")
     .update(code_verifier)
     .digest();

1
投票

完整的工作和验证示例:

const {randomBytes, createHash} = require("node:crypto");
// OR: import {randomBytes, createHash} from "crypto";

function generatePKCEPair() {
    const NUM_OF_BYTES = 22; // Total of 44 characters (1 Bytes = 2 char) (standard states that: 43 chars <= verifier <= 128 chars)
    const HASH_ALG = "sha256";
    const randomVerifier = randomBytes(NUM_OF_BYTES).toString('hex')
    const hash = createHash(HASH_ALG).update(randomVerifier).digest('base64');
    const challenge = hash.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); // Clean base64 to make it URL safe
    return {verifier: randomVerifier, challenge}
}

运行示例:

generatePKCEPair();
// Result:
{
  verifier: '3e2727957a1bd9f47b11ff347fca362b6060941decb4',
  challenge: '1SF5UEwYplIjmAwHUwcitzp9qz8zv98uYflt-tBmwLc'
}
© www.soinside.com 2019 - 2024. All rights reserved.