You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PKCE授权码调用Spotify API时提示code verifier无效

问题排查与修正:Spotify PKCE授权中Code Verifier无效的问题

核心问题分析

  • 随机字符串生成错误:Generate_Random_String函数中,str(values)会把字符列表转为带方括号、引号和逗号的格式(比如['a','b','c']),完全不符合PKCE对code verifier的要求——它必须是指定字符集组成的纯字符串,长度43-128位。
  • 哈希处理逻辑错误:PKCE的S256方法要求对code verifier的原始字节做SHA256哈希,再对哈希的二进制结果做base64 URL安全编码。你的代码错误地将哈希的十六进制字符串作为输入编码,导致code challenge与verifier完全不匹配。

修正后的代码

from dotenv import load_dotenv
import os
import base64
import requests
import random
import hashlib 
from urllib.parse import urlparse, urlunparse, urlencode

load_dotenv()

client_ID = os.getenv("CLIENT_ID")
client_secret = os.getenv("CLIENT_SECRET")


def Generate_Random_String(length):
    possible_Values = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
    # 直接生成随机字符拼接成纯字符串
    return ''.join(random.choice(possible_Values) for _ in range(length))


code_Verifier = Generate_Random_String(64)
# 用with语句安全处理文件写入,自动关闭文件
with open("Code Verifier.txt","w") as perm_code_verifier:
    perm_code_verifier.write(code_Verifier)


def code_hash(plain):
    # 返回SHA256哈希的二进制结果,而非十六进制字符串
    return hashlib.sha256(plain.encode("utf-8")).digest()


def base64encode(hashed_bytes):
    # 对二进制哈希结果做URL安全的base64编码
    auth_base64 = base64.urlsafe_b64encode(hashed_bytes).decode("utf-8")
    # 移除末尾的等号
    return auth_base64.rstrip("=")


hashed = code_hash(code_Verifier)
codeChallenge = base64encode(hashed)

scope = "user-read-private user-read-email"
authURL = urlparse("https://accounts.spotify.com/authorize")
redirectURI = "http://localhost:3000"

parameters = {
    "response_type": "code",
    "client_id": client_ID,
    "scope": scope,
    "code_challenge_method": "S256",
    "code_challenge": codeChallenge,
    "redirect_uri" : redirectURI,
}

authUrl_incl_params = authURL._replace(query=urlencode(parameters))
final_url = urlunparse(authUrl_incl_params)

print("Go to ", final_url, "to authenticate")
code = input("Enter code recieved:")


def get_token(code):
    with open("Code Verifier.txt") as file:
        # 读取时去除可能的换行符,避免空白字符干扰
        codeVerifier = file.read().strip()

    url = "https://accounts.spotify.com/api/token"

    payload = {
        "client_id": client_ID,
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": redirectURI,
        "code_verifier": codeVerifier,
    }

    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
    }
    
    try:
        response = requests.post(url, data=payload, headers=headers)
        response.raise_for_status()  # 主动抛出HTTP错误,便于调试
        response_ans = response.json()
        print(response_ans)
        token = response_ans.get("access_token")
        return token

    except Exception as e:
        print(f"Error: {e}")
        print(f"Response content: {response.text}")  # 打印响应内容,辅助排查其他问题


token = get_token(code)
print(token)

额外优化说明

  • 用with语句处理文件操作,避免资源泄漏。
  • 添加response.raise_for_status()和响应内容打印,方便排查redirect_uri不匹配、code过期等其他潜在问题。
  • 读取code verifier时用strip()去除可能的换行符,防止写入文件时的意外空白导致验证失败。

内容的提问来源于stack exchange,提问作者willow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:14:58