我正在尝试将 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 不正确”。我在这里做错了什么?
这里是重要的部分:
生成代码验证器
// 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;
}
这是一个工作示例
您还可以检查代码的有效性在这里
我从 passport oauth2 库中获取了这个片段来生成代码验证器和代码挑战。
const code_verifier = base64url(crypto.pseudoRandomBytes(32));
const code_challenge = crypto
.createHash("sha256")
.update(code_verifier)
.digest();
完整的工作和验证示例:
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'
}