Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
524 views
in Technique[技术] by (71.8m points)

javascript - Spotify API bad request on api/token authorization Error: 400

I am trying to authorize spotify api requests using Client Credentials Flow on the Spotify API Docs page. Here is my code in javascript ES6 format using the fetch API

    const response = await fetch('https://accounts.spotify.com/api/token', {
    mode: 'no-cors',
    method: 'POST',
    headers: {
      'Authorization': 'Basic Yzg4OWYzMjM5MjI0NGM4MGIyMzIyOTI5ODQ2ZjZmZWQ6MmUzZTM2YTMzMTM5NDM1Mzk3NzM4ZDMxMTg4MzM0Mjc=',
      'Content-type': 'application/x-www-form-urlencoded'
      },
    body: 'grant_type=client_credentials'
});

The console is saying it is a bad request and doesn't return any JSON.

Another thing that really confuses me is that when I send the request using POSTMAN with those headers and that body, it returns exactly what I want (It works) I don't see how this is different from what I'm doing...? Could anyone please help?

Also here is the code from postman in Javascript Jquery Ajax if this helpls:

var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://accounts.spotify.com/api/token",
  "method": "POST",
  "headers": {
    "Authorization": "Basic Yzg4OWYzMjM5MjI0NGM4MGIyMzIyOTI5ODQ2ZjZmZWQ6MmUzZTM2YTMzMTM5NDM1Mzk3NzM4ZDMxMTg4MzM0Mjc=",
    "Content-Type": "application/x-www-form-urlencoded",
    "Cache-Control": "no-cache",
    "Postman-Token": "2f93918d-2e8e-4fb0-a168-7e153dd83912"
  },
  "data": {
    "grant_type": "client_credentials"
  }
}  

$.ajax(settings).done(function (response) {
  console.log(response);
});

This is what the request looks like in DevTools enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

That particular endpoint is not meant to be consumed client side. You are supposed to use it in some server side script.

https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow

The Client Credentials flow is used in server-to-server authentication

Another hint that it is meant to be server side only is that it uses your client secret as its name implies it is meant to be kept secret and having it viewable on the client isn't very secret.

So from that endpoint you get the access token which you can then use on the client side to make requests to the other api endpoints like https://api.spotify.com/v1/tracks

Now as for why it doesn't work in your calls. It works in postman because it ignores CORS, and it properly sends the authorization header. In the browser however you set the fetch() request mode to no-cors. In this mode only certain headers can be sent AND the response back cannot be read by javascript.

Due to this your request does not send the authorization header as it is not one of the simple headers allowed in no-cors mode. And so your request fails. Even if the authorization went through you wouldn't have been able to read the response anyways as per no-cors rules.

So if you want to continue using the Client Credentials flow you would:

  1. From the browser, make a request to your own server.

    fetch("http://myserver.com/getToken")
    
  2. On the server you would then do the https://accounts.spotify.com/api/token request from there sending all the correct information. Then send the returned access token back to the client

    //this is assuming a nodejs server environment
    var postQuery = 'grant_type=client_credentials ';
    var request = require('request');
    var express = require('express');
    var app = express();
    app.get('/getToken', function(req, res){
      request({
        url: "https://accounts.spotify.com/api/token",
        method: "POST",
        headers: {
          'Authorization': 'Basic YourBase64EncodedCredentials',
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': postQuery.length
        },
        body: postQuery
      }, function (error, response, data){
        //send the access token back to client
        res.end(data);
      });    
    });
    
  3. Use that access token in a normal fetch request to the endpoints you need to use as they are setup with the proper CORS headers

    fetch("http://myserver.com/getToken")
    .then(token=>{
      //token will be the token returned from your own server side script
      //now we can make a new request to the tracks (or any other api)
      return fetch("https://api.spotify.com/v1/tracks",{
        headers:{
          'Authorization': `Bearer ${token}`
        }
      }).then(r=>r.json())
    })
    .then(data=>{
       //data will be the data returned from tracks api endpoint
     });
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...