Home > Blockchain >  Spotify returning 200 on token endpoint, but response data is encoded
Spotify returning 200 on token endpoint, but response data is encoded

Time:11-28

I'm working through this tutorial on creating an app that uses the Spotify API. Everything was going great until I got to the callback portion of authenticating using the authentication code flow.

(I do have my callback URL registered in my Spotify app.)

As far as I can tell, my code matches the callback route that this tutorial and others use. Significantly, the http library is axios. Here's the callback method:

app.get("/callback", (req, res) => {
        const code = req.query.code || null;

        const usp = new URLSearchParams({
            code: code,
            redirect_uri: REDIRECT_URI,
            grant_type: "authorization_code",
        });

        axios({
                    method: "post",
                    url: "https://accounts.spotify.com/api/token",
                    data: usp,
                    headers: {
                        "content-type": "application/x-www-form-urlencoded",
                        Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64")}`,
  },
})
  .then(response => {
    console.log(response.status); // logs 200
    console.log(response.data); // logs encoded strings
    if (response.status === 200) {
      res.send(JSON.stringify(response.data))
    } else {
      res.send(response);
    }
  })
  .catch((error) => {
    res.send(error);
  });

Though the response code is 200, here's a sample of what is getting returned in response.data: "\u001f�\b\u0000\u0000\u0000\u0000\u0000\u0000\u0003E�˒�0\u0000Ee�uS\u0015��\u000e�(\b\u0012h\u0005tC%\u0010\u0014T\u001e�����0��^޳:���p\u0014Ѻ\u000e��Is�7�:��\u0015l��ᑰ�g�����\u0"

It looks like it's encoded, but I don't know how (I tried base-64 unencoding) or why it isn't just coming back as regular JSON. This isn't just preventing me logging it to the console - I also can't access the fields I expect there to be in the response body, like access_token. Is there some argument I can pass to axios to say 'this should be json?'

Interestingly, if I use the npm 'request' package instead of axios, and pass the 'json: true' argument to it, I'm getting a valid token that I can print out and view as a regular old string. Below is code that works. But I'd really like to understand why my axios method doesn't.

app.get('/callback', function(req, res) {
        // your application requests refresh and access tokens
        // after checking the state parameter

        const code = req.query.code || null;
        const state = req.query.state || null;
        const storedState = req.cookies ? req.cookies[stateKey] : null;

        res.clearCookie(stateKey);
        const authOptions = {
                url: 'https://accounts.spotify.com/api/token',
                form: {
                    code: code,
                    redirect_uri: REDIRECT_URI,
                    grant_type: 'authorization_code',
                },
                headers: {
                    Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64')}`,
                },
                json: true,
    };

  request.post(authOptions, function (error, response, body) {
    if (!error && response.statusCode === 200) {
      const access_token = body.access_token;
      const refresh_token = body.refresh_token;

      var options = {
        url: 'https://api.spotify.com/v1/me',
        headers: { Authorization: 'Bearer '   access_token },
        json: true,
    };

    // use the access token to access the Spotify Web API
    request.get(options, function(error, response, body) {
        console.log(body);
    });
    // we can also pass the token to the browser to make requests from there
    res.redirect('/#'   querystring.stringify({
        access_token: access_token,
        refresh_token: refresh_token,
    }));
    } else {
      res.redirect(`/#${querystring.stringify({ error: 'invalid_token' })}`);
    }
  });

});

CodePudding user response:

You need to add Accept-Encoding with application/json in axios.post header.

The default of it is gzip

headers: {
   "content-type": "application/x-www-form-urlencoded",
   'Accept-Encoding': 'application/json'
   Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64")}`,
  }
  • Related