nodejs express + create-react-app oauth2.0 错误 401 'Invalid access token' Spotify API

nodejs express + create-react-app oauth2.0 error 401 'Invalid access token' Spotify API

我正在尝试构建一个允许我通过 nodejs express 服务器从 create-react-app 客户端调用 Spotify 的 API 的应用程序。我正在尝试使用 Authorization Code Flow.

它可以使用以下代码获取授权代码以生成 URL,完全在客户端(是否以及如何使用服务器端是另一个问题):

getSpotifyCodeUrl() {
  const authEndPoint = 'https://accounts.spotify.com/authorize'
  const clientId = CLIENT_ID;
  const responseType = 'code';
  const redirectUrl = 'http://localhost:3000/';
  // TODO: state for cross-site request forgery protection
  // cont state = '...';
  const scope = 'user-read-private user-read-email';
  return(
    authEndPoint +
    '?response_type=' + responseType +
    '&client_id=' + clientId +
    (scope ? '&scope=' + encodeURIComponent(scope) : '') +
    '&redirect_uri=' + encodeURIComponent(redirectUrl)
  )
}

用户只需单击带有上面生成的 href 的 link。

{!this.state.token ? <a className="btn btn--loginApp-link" href={this.getSpotifyCodeUrl()}>
  Login to Spotify
</a> : ""}

用户重定向回来后,我使用以下函数从

中提取授权码
componentDidMount() {
  this.setState({code: new URLSearchParams(window.location.search).get('code')});
}

使用代码我检索了访问令牌。客户来电:

getSpotifyAccessToken() {
  fetch('/auth?code=' + this.state.code)
    .then((res) => res.json())
    .then(data => {
      this.setState({token: data.token});
      localStorage.setItem('token', this.state.token);
    });
}

API 在服务器上调用:

app.get("/auth", (req, res) => {
  let code = req.query.code;
  let authOptions = {
    url: 'https://accounts.spotify.com/api/token',
    form: {
      code: code,
      redirect_uri: 'http://localhost:3000/',
      grant_type: 'authorization_code'
    },
    headers: {
      'Authorization': 'Basic ' + (new Buffer.from(clientId + ':' + clientSecret).toString('base64'))
    },
    json: true
  };

  request.post(authOptions, function(error, response, body){
    if (!error && response.statusCode === 200) {
      token = body.access_token;
      res.json({ token: "Token: " + body.access_token});
    } else { 
      console.log("/auth response body")
      console.log(body) 
    } 
  });
});

奇怪的是我得到了一个令牌,但在我的服务器终端中也可以看到以下错误:

{ error: 'invalid_grant', error_description: 'Invalid authorization code' }

如果我随后尝试使用该令牌执行来自客户端的(简单)请求:\

getSpotifyMe() {
  fetch('/me?token=' + this.state.token)
    .then((res) => res.json())
    .then(data => {
      console.log(data);
    });
}

以及相应的服务器调用:

app.get("/me", (req, res) => {
  let token = req.query.token;
  console.log("Token: " + token);
  let options = {
    url: 'https://api.spotify.com/v1/me',
    headers: { 'Authorization': 'Bearer ' + token },
    json: true
  }

  request.get(options, function(error, response, body) {
    console.log("/me request body");
    console.log(body);
    if (!error && response.statusCode === 200) {
      res.json(body);
    } else {
    } 
  })
})

这给我一个 401 错误:

{ error: { status: 401, message: 'Invalid access token' } }

我已经尝试了一些东西。从客户那里打电话,没有成功。刷新令牌,删除 cookie,从帐户授权,但没有成功。奇怪的是我可以使用据说在 Spotify Web Console 中无效的令牌,执行与我在应用程序中尝试执行的完全相同的调用。

您知道我在应用程序中的什么地方导致了这些错误(invalid_grant 和 401)吗?我该如何解决它们?

我最终更密切地关注 the example on Spotify GitHub

我将 create-react-app 更改为简单地调用 /login 服务器路由。不要像我尝试的那样使用 fetch,一旦服务器从不同的来源调用 Spotify API,你最终会遇到跨域错误。由于某些不明显的原因,我无法使用 href="/login",服务器根本没有响应,但这是另一个 SO 问题的结果。

<a href="http://localhost:3001/login">Login to Spotify</a>

服务器 index.js 现在只是授权代码流 app.js,带有我自己的变量和一个小调整。

  • 我的 redirect_urihttp://localhost:3001/callback,我在 http://localhost:3000 重定向回我的客户 create-react-app 时费了好大劲儿,也许这就是问题所在授权码和访问令牌,IDK。您想直接进入 服务器端 回调。对用户来说也更加直观:点击一下,砰的一声,登录,中间没有乱七八糟的重定向。
  • 在服务器上的 /callback 路由中,当 access_tokenrefresh_token 已成功检索或未成功检索时,这就是您要重定向回客户端的时候,http://localhost:3000 对我来说。当然有代币。该示例使用 URL 参数,我猜设置 cookie 也应该有效,但如果这是安全问题,则必须进行一些研究。

我对应用程序的 CORS 子句进行了小小的调整。除了来自我的客户端之外,服务器不需要传入请求,所以我在那里添加了一个 {origin: 'http://localhost:3000'} 以防万一。

 app.use(express.static(__dirname + '../client/build'))
    .use(cors({origin: 'http://localhost:3000'}))
    .use(cookieParser());  

就是这样,非常有效,我可以看到服务器端收到 /v1/me 调用的响应主体(示例代码中有一个控制台日志)并且令牌正在返回客户端.