在 Spotify API 集成中交换访问令牌的授权代码时出现 400 错误

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

我正在努力使用 PKCE Flow 的授权代码将 Spotify API 集成到我的 Web 应用程序中。我已遵循 Spotify 提供的文档,但在尝试用授权代码交换访问令牌时遇到 400 错误。

这是我所做的总结:

  • 实现了 PKCE 扩展以生成代码验证器和代码质询。
  • 使用适当的参数(包括代码挑战)将用户重定向到 Spotify 的授权页面。
  • 用户授予权限后,在回调URL中收到授权码。
  • 尝试使用对 Spotify 令牌端点的 POST 请求来交换访问令牌的授权代码。

但是,将授权代码交换为访问令牌的 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 状态代码和一条指出“无效授权代码”的消息之外,它没有提供太多信息。我相信这是由于授权码过期造成的,但我不知道如何解决这个问题。

任何有关可能导致此问题的原因的见解或建议将不胜感激。谢谢!

javascript reactjs oauth-2.0 spotify pkce
1个回答
0
投票

我遇到了同样的问题,我发现授权码在使用后就会过期,并且仅在使用一次后就会过时。该流程在授权提示后运行良好,但在重新加载时运行不佳。

所以我的解决方法是存储信息“post_authorization”。

  • 如果为 True,我们会根据从 window.location 获取的“代码”生成一个令牌
  • 如果为 False,要么我们已经有了 access_token 并且可以进入下一步,要么没有,我们需要另一个授权

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);
}

© www.soinside.com 2019 - 2024. All rights reserved.