Announcements

Help Wizard

Step 1

NEXT STEP

FAQs

Please see below the most popular frequently asked questions.

Loading article...

Loading faqs...

VIEW ALL

Ongoing Issues

Please see below the current ongoing issues which are under investigation.

Loading issue...

Loading ongoing issues...

VIEW ALL

403 error on GET v1/me/top/tracks

Solved!

403 error on GET v1/me/top/tracks

hello,

i have been working on an app that uses spotify API and one of the things i need to do is get access to the top 25 tracks in a specified time range. the issue is that i keep getting a 403 error when i send get requests. i have spent hours trying to modify my code in hopes of fixing the issue, but nothing is happening. is there something wrong with my function that calls the get requests, or is the problem somewhere else, such as my access token or my approach to authorization? here is my fetchTopSongs function: 

const fetchTopSongs = async (accessToken) => {
    try {
      const response = await fetch(`https://api.spotify.com/v1/me/top/tracks?time_range=${timeRange}&limit=25`, {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      });
      const data = await response.json();
      setTopSongs(data.items)
      console.log(topSongs);
    } catch (error) {
      console.log(error);
    }
  };
Reply

Accepted Solutions
Marked as solution

I knew it! "grant_type=client_credentials".

"Since [the Client Credentials] flow does not include authorization, only endpoints that do not access user information can be accessed."

XimzendSpotify Star
Help others find this answer and click "Accept as Solution".
If you appreciate my answer, maybe give me a Like.
Note: I'm not a Spotify employee.

View solution in original post

11 Replies

Error 403 means "Bad OAuth request". Are you using Client Credentials?

XimzendSpotify Star
Help others find this answer and click "Accept as Solution".
If you appreciate my answer, maybe give me a Like.
Note: I'm not a Spotify employee.

thanks for your response,

i think im doing authorization code flow. this is a react app, so i look in the console for errors and i see the 403 error next to the get request along with an axios error when i implement with axios and some form of incomplete json error when implementing with fetch. this might be because i am sending a bad request though (i.e. not getting data back). i'm sure the error is somewhere in making a valid OAuth request. what should i do to ensure that i am doing this correctly. does my code here look wrong? or do you think the error is somewhere else?

You didn't include code on how your app requests an access token. I think there is the mistake.

XimzendSpotify Star
Help others find this answer and click "Accept as Solution".
If you appreciate my answer, maybe give me a Like.
Note: I'm not a Spotify employee.

i did some more reading and i think I'm missing a refreshToken method but that doesn't concern me right now because newly generated access tokens are not working with the get requests, so I'm trying to fix that first. this is my getAccessToken method: 

const getAccessToken = async () => {
    const response = await axios.post(
      `grant_type=client_credentials`,
      {
        headers: {
          Authorization: `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}`,
          "Content-Type": "application/x-www-form-urlencoded",
        },
      }
    );
    var token = response.data.access_token;
    setAccessToken(token);
  };

here is all my code, this should clear up any confusion:

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import './App.css';

const CLIENT_ID = 'i have the client id here in my IDE';
const CLIENT_SECRET = 'i have the client secret here in my IDE';
const REDIRECT_URI = 'http://localhost:3000/callback';
const SCOPES = 'user-top-read';
var urlCode = null;

const App = () => {
  const [accessToken, setAccessToken] = useState(null);
  const [timeRange, setTimeRange] = useState('short_term');
  const [topSongs, setTopSongs] = useState([]);
  const [auraColor, setAuraColor] = useState('#000000');


  const handleTimeRangeChange = (event) => {
    setTimeRange(event.target.value);
  };

  const setCode = async () => {
    const queryString = window.location.search;
    if (queryString.length > 0) {
      const urlParams = new URLSearchParams(queryString);
      urlCode = urlParams.get('code');
    }
  };
  const getAccessToken = async () => {
    const response = await axios.post(
      `grant_type=client_credentials`,
      {
        headers: {
          Authorization: `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}`,
          "Content-Type": "application/x-www-form-urlencoded",
        },
      }
    );
    var token = response.data.access_token;
    setAccessToken(token);
    console.log(urlCode);
    console.log(accessToken);
  };

  useEffect(() => {
    const handleAuthentication = async () => {
      setCode()
      if (urlCode) {
        try {
          await getAccessToken();
          window.history.pushState({}, '', '/');
        } catch (error) {
          console.error('Error retrieving access token:', error);
        }
      }
    };
    handleAuthentication();
  }, []);

  const fetchTopSongs = async () => {
    getAccessToken();
    try {
      const response = await axios ( {
        method: 'GET',
        url: `https://api.spotify.com/v1/me/top/tracks?time_range=${timeRange}&limit=25`,
        headers: { Authorization: `Bearer ${accessToken}`},
      })
      setTopSongs(response.data.items);
      console.log(topSongs);
    } catch (error) {
      console.log(error);
    }
  };

  const getSongColor = async (trackId) => {
    try {
      const response = await axios.get(
        `https://api.spotify.com/v1/tracks/${trackId}`,
        {
          headers: {
            Authorization: `Bearer ${accessToken}`,
          },
        }
      );
    } catch (error) {
      console.error(`Error retrieving song color for track ${trackId}:`, error);
      return null;
    }
  };

  const AUTH_URL = `https://accounts.spotify.com/authorize?client_id=${CLIENT_ID}&response_type=code&redirect_uri=${encodeURIComponent(
    REDIRECT_URI
  )}&scope=${encodeURIComponent(SCOPES)}`;

  return (
    <div className="App">
      <h1 className="app-title">Spotify Aesthetic Aura Generator</h1>
      <div className="aura-color" style={{ backgroundColor: auraColor }}></div>

      {!accessToken && (
        <a href={AUTH_URL} className="spotify-login-button">
          Log in with Spotify
        </a>
      )}

      {accessToken && (
        <div className="time-range-selector">
          <label htmlFor="time-range" className="time-range-label">
            Select Time Range:
          </label>
          <select
            id="time-range"
            value={timeRange}
            onChange={handleTimeRangeChange}
            className="time-range-select"
          >
            <option value="short_term">Last Month</option>
            <option value="medium_term">Last 6 Months</option>
            <option value="long_term">All Time</option>
          </select>
        </div>
      )}

      {accessToken && (
        <button className="generate-button" onClick={() => fetchTopSongs()}>
          Generate Aura
        </button>
      )}

      {topSongs.length > 0 && (
        <div className="song-list">
          <h2 className="song-list-title">Top 25 Songs:</h2>
          <ul className="song-list-items">
            {topSongs.map((song) => (
              <li key={song.id} className="song-list-item">
                <div className="song-color" style={{ backgroundColor: song.color }}></div>
                <div className="song-details">
                  <p className="song-name">{song.name}</p>
                  <p className="song-artist">{song.artist}</p>
                </div>
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
};

export default App;
Marked as solution

I knew it! "grant_type=client_credentials".

"Since [the Client Credentials] flow does not include authorization, only endpoints that do not access user information can be accessed."

XimzendSpotify Star
Help others find this answer and click "Accept as Solution".
If you appreciate my answer, maybe give me a Like.
Note: I'm not a Spotify employee.

The following code should work, according to Chat-GPT:

 

import React, { useEffect, useState } from 'react';

import axios from 'axios';

import './App.css';

 

const CLIENT_ID = 'your_client_id';

const CLIENT_SECRET = 'your_client_secret';

const REDIRECT_URI = 'http://localhost:3000/callback';

const SCOPES = 'user-top-read';

var urlCode = null;

 

const App = () => {

  const [accessToken, setAccessToken] = useState(null);

  const [timeRange, setTimeRange] = useState('short_term');

  const [topSongs, setTopSongs] = useState([]);

  const [auraColor, setAuraColor] = useState('#000000');

 

  const handleTimeRangeChange = (event) => {

    setTimeRange(event.target.value);

  };

 

  const setCode = async () => {

    const queryString = window.location.search;

    if (queryString.length > 0) {

      const urlParams = new URLSearchParams(queryString);

      urlCode = urlParams.get('code');

    }

  };

 

  const getAccessToken = async () => {

    const response = await axios.post(

      'https://accounts.spotify.com/api/token',

      new URLSearchParams({

        grant_type: 'authorization_code',

        code: urlCode,

        redirect_uri: REDIRECT_URI,

        client_id: CLIENT_ID,

        client_secret: CLIENT_SECRET,

      }).toString(),

      {

        headers: {

          'Content-Type': 'application/x-www-form-urlencoded',

        },

      }

    );

 

    const token = response.data.access_token;

    setAccessToken(token);

  };

 

  useEffect(() => {

    const handleAuthentication = async () => {

      await setCode();

      if (urlCode) {

        try {

          await getAccessToken();

          window.history.pushState({}, '', '/');

        } catch (error) {

          console.error('Error retrieving access token:', error);

        }

      }

    };

 

    handleAuthentication();

  }, []);

 

  const fetchTopSongs = async () => {

    try {

      const response = await axios.get(

        `https://api.spotify.com/v1/me/top/tracks?time_range=${timeRange}&limit=25`,

        {

          headers: { Authorization: `Bearer ${accessToken}` },

        }

      );

      setTopSongs(response.data.items);

    } catch (error) {

      console.log('Error retrieving top songs:', error);

    }

  };

 

  const getSongColor = async (trackId) => {

    try {

      const response = await axios.get(`https://api.spotify.com/v1/tracks/${trackId}`, {

        headers: {

          Authorization: `Bearer ${accessToken}`,

        },

      });

      // Handle the song color response

    } catch (error) {

      console.error(`Error retrieving song color for track ${trackId}:`, error);

    }

  };

 

  const AUTH_URL = `https://accounts.spotify.com/authorize?client_id=${CLIENT_ID}&response_type=code&redirect_uri=${enco...(

    REDIRECT_URI

  )}&scope=${encodeURIComponent(SCOPES)}`;

 

  return (

    <div className="App">

      <h1 className="app-title">Spotify Aesthetic Aura Generator</h1>

      <div className="aura-color" style={{ backgroundColor: auraColor }}></div>

 

      {!accessToken && (

        <a href={AUTH_URL} className="spotify-login-button">

          Log in with Spotify

        </a>

      )}

 

      {accessToken && (

        <div className="time-range-selector">

          <label htmlFor="time-range" className="time-range-label">

            Select Time Range:

          </label>

          <select

            id="time-range"

            value={timeRange}

            onChange={handleTimeRangeChange}

            className="time-range-select"

          >

            <option value="short_term">Last Month</option>

            <option value="medium_term">Last 6 Months</option>

            <option value="long_term">All Time</option>

          </select>

        </div>

      )}

 

      {accessToken && (

        <button className="generate-button" onClick={() => fetchTopSongs()}>

          Generate Aura

        </button>

      )}

 

      {topSongs.length > 0 && (

        <div className="song-list">

          <h2 className="song-list-title">Top 25 Songs:</h2>

          <ul className="song-list-items">

            {topSongs.map((song) => (

              <li key={song.id} className="song-list-item">

                <div className="song-color" style={{ backgroundColor: song.color }}></div>

                <div className="song-details">

                  <p className="song-name">{song.name}</p>

                  <p className="song-artist">{song.artist}</p

>

                </div>

              </li>

            ))}

          </ul>

        </div>

      )}

    </div>

  );

};

 

export default App;

XimzendSpotify Star
Help others find this answer and click "Accept as Solution".
If you appreciate my answer, maybe give me a Like.
Note: I'm not a Spotify employee.

yeah i guess i didn't read the documentation well enough, im new to spotify API and its been interesting working with it. but its good that i know now, thanks to you. you're the best!

so it's impossible to show the top items to a client

 

If you implement the Authorization Code Flow, you can display the top tracks of a user after they log in. Not with Client Credentials, because with that, you can't let a user log in.

XimzendSpotify Star
Help others find this answer and click "Accept as Solution".
If you appreciate my answer, maybe give me a Like.
Note: I'm not a Spotify employee.

thanks 

 

Suggested posts

Let's introduce ourselves!

Hey there you,   Yeah, you! 😁   Welcome - we're glad you joined the Spotify Community!   While you here, let's have a fun game and get…

ModeratorStaff / Moderator/ 4 years ago  in Social & Random