我正在努力使用 PKCE Flow 的授权代码将 Spotify API 集成到我的 Web 应用程序中。我已遵循 Spotify 提供的文档,但在尝试用授权代码交换访问令牌时遇到 400 错误。
这是我所做的总结:
但是,将授权代码交换为访问令牌的 POST 请求失败,并出现 400 错误。我仔细检查了参数,包括 client_id、grant_type、redirect_uri、code_verifier 和 code,它们似乎都是正确的。
这是我正在使用的代码的简化版本:
const clientId = [YOUR_CLIENT_ID];
const redirectUri = 'http://localhost:3000';
const generateAuthCode = async () => {
// Generate code verifier
const codeVerifier = 'generated_code_verifier';
// Redirect user to Spotify authorization page
const authUrl = 'https://accounts.spotify.com/authorize';
const params = {
response_type: 'code',
client_id: clientId,
scope: 'playlist-modify-public playlist-modify-private',
code_challenge_method: 'S256',
code_challenge: 'generated_code_challenge',
redirect_uri: redirectUri,
};
const queryString = new URLSearchParams(params).toString();
window.location.href = `${authUrl}?${queryString}`;
};
const generateAccessToken = async (code, setUserInfo) => {
// Exchange authorization code for access token
const url = 'https://accounts.spotify.com/api/token';
const payload = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: clientId,
grant_type: 'authorization_code',
code,
redirect_uri: redirectUri,
code_verifier: 'stored_code_verifier',
}),
};
try {
const response = await fetch(url, payload);
const responseData = await response.json();
setUserInfo((prevInfo) => ({
api_key: responseData.access_token,
userId: prevInfo.userId,
}));
} catch (error) {
console.log('Error:', error);
}
};
export { generateAuthCode, generateAccessToken };
我还记录了服务器的响应,但除了 400 状态代码和一条指出“无效授权代码”的消息之外,它没有提供太多信息。我相信这是由于授权码过期造成的,但我不知道如何解决这个问题。
任何有关可能导致此问题的原因的见解或建议将不胜感激。谢谢!
我遇到了同样的问题,我发现授权码在使用后就会过期,并且仅在使用一次后就会过时。该流程在授权提示后运行良好,但在重新加载时运行不佳。
所以我的解决方法是存储信息“post_authorization”。
const appClientId = "your client id";
const redirectUri = 'http://localhost:5173/callback';
const accessToken = localStorage.getItem("access_token");
var postAuthorization = localStorage.getItem("post_authorization")
console.log("postAuthorization: " + postAuthorization)
console.log("accessToken: " + accessToken)
if ((!accessToken || accessToken === 'undefined') && (!postAuthorization || postAuthorization === 'no')) {
console.log("Auth flow");
localStorage.setItem('post_authorization', 'yes')
redirectToAuthCodeFlow(appClientId);
} else if (postAuthorization === 'yes') {
console.log("Post Auth flow");
const params = new URLSearchParams(window.location.search);
const userCode = params.get("code");
const accessToken = await getAccessToken(appClientId, userCode);
localStorage.setItem('access_token', accessToken); // Store the access token
console.log("accessToken is saved to "+accessToken)
let postAuthorization = 'no';
localStorage.setItem('post_authorization', "no"); // Can now connect directly with the access token
const profile = await fetchProfile(accessToken);
populateUI(profile);
} else {
console.log("Post Access Token");
const profile = await fetchProfile(accessToken);
populateUI(profile);
}