Getting 403 Error When Fetching User's Favorite Artists and Genres via Spotify Web API

Issue Description

I’m building a music-based web application using HTML/CSS and the Spotify Web API. The authentication process works fine, but I keep running into a 403 error when trying to access user data. The strange thing is that it only works if I manually add the testing account to my app’s user dashboard on the Spotify developer portal.

Error messages I’m seeing:

  • “Failed to load resource: the server responded with a status of 403 ()”
  • “Error fetching artist data: Check settings on spotify-for-developers, the user may not be registered.”

Code Implementation

main.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Music Style Generator</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div class="welcome-section">
    <div class="content-wrapper">
      <h1 class="main-heading">
        <span>DISCOVER</span>
        <span>YOUR</span>
        <span>MUSIC</span>
        <span>STYLE</span>
      </h1>
      <p class="description">Generate recommendations based on your listening habits</p>
      <a href="https://accounts.spotify.com/authorize?client_id=your_client_id&response_type=code&redirect_uri=your_redirect_uri&scope=user-read-private,user-top-read,user-read-email" class="auth-button">
        <img src="spotify-icon.png" alt="Spotify" class="icon">
        Authorize with Spotify
      </a>
    </div>
  </div>

  <div class="data-section" style="display: none;">
    <div class="content-wrapper">
      <h2>Your Primary Genre:</h2>
      <p class="genre-display">Loading...</p>
      <h3>Your Favorite Artist:</h3>
      <p class="artist-display"></p>
      <img class="artist-photo" src="placeholder.jpg" alt="Artist Photo">
    </div>
  </div>

  <script>
    function extractTokenFromUrl() {
      const urlHash = window.location.hash.substring(1);
      const parameters = new URLSearchParams(urlHash);
      return parameters.get("access_token");
    }

    function parseAccessToken() {
      let token = null;
      const hashString = window.location.hash.substring(1);
      const paramArray = hashString.split('&');
      for (let j = 0; j < paramArray.length; j++) {
        const keyValue = paramArray[j].split('=');
        if (keyValue[0] === 'access_token') {
          token = keyValue[1];
          break;
        }
      }
      return token;
    }

    window.addEventListener("load", function() {
      const userToken = parseAccessToken();
      if (userToken) {
        sessionStorage.setItem('spotifyToken', userToken);
        window.location.href = 'dashboard.html';
      }
    });
  </script>
</body>
</html>

dashboard.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Music Dashboard</title>
  <link rel="stylesheet" href="dashboard.css">
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script>
    document.addEventListener("DOMContentLoaded", function() {
      const appId = 'your_client_id';
      const appSecret = 'your_client_secret';
      const callbackUrl = 'your_redirect_uri';

      const queryParams = new URLSearchParams(window.location.search);
      const authorizationCode = queryParams.get('code');
      
      if (authorizationCode) {
        getAccessToken(authorizationCode);
      } else {
        initiateSpotifyAuth();
      }

      function initiateSpotifyAuth() {
        const permissions = 'user-read-private user-read-email user-top-read user-read-recently-played';
        const authEndpoint = `https://accounts.spotify.com/authorize?client_id=${appId}&response_type=code&redirect_uri=${encodeURIComponent(callbackUrl)}&scope=${encodeURIComponent(permissions)}`;
        window.location.href = authEndpoint;
      }

      function getAccessToken(authCode) {
        $.ajax({
          url: "https://accounts.spotify.com/api/token",
          method: "POST",
          headers: {
            "Authorization": "Basic " + btoa(`${appId}:${appSecret}`)
          },
          data: {
            grant_type: "authorization_code",
            code: authCode,
            redirect_uri: callbackUrl
          },
          success: function(data) {
            const userToken = data.access_token;
            loadUserMusicData(userToken);
          },
          error: function(xhr, status, error) {
            console.error("Token exchange failed:", xhr.responseText || error);
          }
        });
      }

      function loadUserMusicData(token) {
        $.ajax({
          url: "https://api.spotify.com/v1/me/top/artists?time_range=medium_term&limit=1",
          method: "GET",
          headers: {
            "Authorization": "Bearer " + token
          },
          success: function(data) {
            const genreDisplay = $('#primaryGenre');
            const artistSection = $('#top-artist-section');
            const artistNameDisplay = $('#topArtistName');
            const artistPhotoDisplay = $('#topArtistPhoto');

            if (data.items.length > 0) {
              const favoriteArtist = data.items[0];
              const musicGenres = favoriteArtist.genres;
              const artistTitle = favoriteArtist.name;
              const artistPhoto = favoriteArtist.images.length > 0 ? favoriteArtist.images[0].url : null;

              const primaryGenre = musicGenres.length > 0 ? musicGenres[0] : "Genre not found";
              genreDisplay.text(primaryGenre);
              artistNameDisplay.text(artistTitle);
              
              if (artistPhoto) {
                artistPhotoDisplay.attr('src', artistPhoto).show();
              } else {
                artistPhotoDisplay.hide();
              }
              artistSection.show();
            } else {
              genreDisplay.text("No music data found.");
              artistSection.hide();
            }
          },
          error: function(xhr, status, error) {
            console.error("Failed to load music data:", xhr.responseText || error);
          }
        });
      }
    });
  </script>
</head>
<body>
  <div class="dashboard-page">
    <div class="dashboard-wrapper">
      <h1 class="primary-genre-heading">Your top music genre is...</h1>
      <h2 id="primaryGenre" class="genre-result">Loading...</h2>

      <div id="top-artist-section" class="artist-section" style="display: none;">
        <h3 class="artist-heading">Your Most Played Artist:</h3>
        <p id="topArtistName" class="artist-result"></p>
        <img id="topArtistPhoto" alt="Artist" class="artist-photo" style="width: 250px; height: auto; border-radius: 8px;" />
      </div>
    </div>
  </div>
</body>
</html>

I’ve tried expanding the scope permissions to include user-read-playback-state and user-modify-playback-state, but the 403 error persists. The app only works when I manually whitelist user accounts in the developer dashboard. Any ideas on what might be causing this restriction?

your app’s stuck in dev mode on spotify’s dashboard. u need to submit it for extended quota mode or request prod access - for now it only works for test users u’ve manually added. check the app status section in your dev console.

Ugh, this sucks - just went through this a few months back. You’re hitting the 25 user limit in dev mode. Spotify blocks anyone not whitelisted with a 403 error right away. Your only options are getting quota extension approval (which takes forever) or manually adding users through the dashboard.

Been dealing with Spotify API integration for two years and hit this same issue early on. You’re getting 403 errors because your app’s stuck in development mode, which only lets users you’ve manually added access it.

Most people miss this - check your app’s user limit in the dashboard. Should say “25 users” if you’re in dev mode. Spotify blocks any unauthorized user as a security risk, so you get the 403.

I worked around this by making multiple test accounts and adding them all to the dashboard. But for production, you’ll need to request a quota extension. Get your privacy policy and terms of service tight first - they review those documents hard during approval.

Classic Spotify dev environment problem. You’re stuck in development mode, which caps you at 25 manually-added users through the dashboard. Those 403 errors? Spotify’s blocking anyone you haven’t specifically whitelisted.

You’ve got two choices: submit for a quota extension or keep manually adding test users. I dealt with this nightmare last year - the extension process drags on for 2-3 weeks and they want tons of documentation about what your app does.

Before you submit, make sure your app description clearly explains everything and you’re not breaking their content rules. They’re pretty picky about approving these requests.