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

Status 403 for playing/resuming song

Solved!

Status 403 for playing/resuming song

I have premium account and signed through client credentials authorization, but I still get that message with status 403 and can't understand why. Could someone please help me?

 

 

 

 

 

 

 

 

    const access_token = (
      await axios({
        method: "POST",
        data: {
          grant_type: "client_credentials",
          scope: "user-modify-playback-state user-top-read",
        },
        url: "https://accounts.spotify.com/api/token",
        headers: {
          Authorization: `Basic ${Buffer.from(
            this.clientId + ":" + this.clientSecret
          ).toString("base64")}`,

          "Content-Type": "application/x-www-form-urlencoded",
        },
      })
    ).data.access_token;

    try {
      let res = await axios({
        method: "PUT",
        url: "https://api.spotify.com/v1/me/player/play",
        headers: {
          Authorization: `Bearer ${access_token}`,
          "Content-Type": "application/json",
        },
        data: {
          context_uri: "spotify:album:5ht7ItJgpBH7W6vJ5BqpPr",
        },
      });

      console.log("ARTIST", res);
    } catch (err: any) {
      // 403 status
      console.log("THIS ERRROR\n ", err.response);
    }

 

 

 

 

 

 

 

 

Reply

Accepted Solutions
Marked as solution

Here's an example Node.js app, without the need for installing any modules. You have to be able to see the console on your server, though.

const http = require('http');
const url = require('url');
const querystring = require('querystring');
const https = require('https');

const clientId = 'YOUR_CLIENT_ID';
const clientSecret = 'YOUR_CLIENT_SECRET';
const redirectUri = 'http://localhost:3000/callback';
const scopes = ['user-modify-playback-state', 'user-top-read', 'user-read-playback-state'];

// Step 1: Get authorization code
function authorize() {
  const authorizeUrl = 'https://accounts.spotify.com/authorize';
  const queryParams = querystring.stringify({
    response_type: 'code',
    client_id: clientId,
    scope: scopes.join(' '),
    redirect_uri: redirectUri,
  });
  const authorizationUrl = `${authorizeUrl}?${queryParams}`;
  console.log(`Please authorize the application by visiting this URL: ${authorizationUrl}`);
}

// Step 2: Get access and refresh tokens
async function getTokens(authorizationCode) {
  const tokenUrl = 'https://accounts.spotify.com/api/token';
  const data = querystring.stringify({
    grant_type: 'authorization_code',
    code: authorizationCode,
    redirect_uri: redirectUri,
  });
  const authHeader = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');

  const options = {
    hostname: 'accounts.spotify.com',
    path: '/api/token',
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Authorization: `Basic ${authHeader}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data));
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.write(data);
    req.end();
  });
}

// Step 3: Refresh access token
async function refreshAccessToken(refreshToken) {
  const tokenUrl = 'https://accounts.spotify.com/api/token';
  const data = querystring.stringify({
    grant_type: 'refresh_token',
    refresh_token: refreshToken,
  });
  const authHeader = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');

  const options = {
    hostname: 'accounts.spotify.com',
    path: '/api/token',
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Authorization: `Basic ${authHeader}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data));
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.write(data);
    req.end();
  });
}

// Step 4: Example usage
async function exampleUsage(accessToken) {
  // Get the user's top tracks
  const topTracks = await getTopTracks(accessToken);

  if (topTracks.length === 0) {
    console.log('No top tracks found.');
    return;
  }

  // Retrieve the album of the first top track
  const topTrack = topTracks[0];
  const album = await getAlbum(accessToken, topTrack.album.id);

  if (!album) {
    console.log('No album found.');
    return;
  }

  // Get the user's available devices
  const devices = await getAvailableDevices(accessToken);

  if (devices.length === 0) {
    console.log('No devices found.');
    return;
  }

  // Retrieve the device ID of the first available device
  const deviceId = devices[0].id;

  // Play the album on the first available device
  await playAlbum(accessToken, deviceId, album.uri);

  console.log(`Playing album "${album.name}" by ${album.artists[0].name}`);
}

// Example function: Get the user's top tracks
async function getTopTracks(accessToken) {
  const topTracksUrl = 'https://api.spotify.com/v1/me/top/tracks';

  const options = {
    hostname: 'api.spotify.com',
    path: '/v1/me/top/tracks',
    method: 'GET',
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data).items);
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.end();
  });
}

// Example function: Get album details
async function getAlbum(accessToken, albumId) {
  const albumUrl = `https://api.spotify.com/v1/albums/${albumId}`;

  const options = {
    hostname: 'api.spotify.com',
    path: `/v1/albums/${albumId}`,
    method: 'GET',
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data));
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.end();
  });
}

// Example function: Get available devices
async function getAvailableDevices(accessToken) {
  const devicesUrl = 'https://api.spotify.com/v1/me/player/devices';

  const options = {
    hostname: 'api.spotify.com',
    path: '/v1/me/player/devices',
    method: 'GET',
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data).devices);
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.end();
  });
}

// Example function: Play album on device
async function playAlbum(accessToken, deviceId, albumUri) {
  const playbackUrl = `https://api.spotify.com/v1/me/player/play?device_id=${deviceId}`;

  const options = {
    hostname: 'api.spotify.com',
    path: `/v1/me/player/play?device_id=${deviceId}`,
    method: 'PUT',
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
  };

  const data = JSON.stringify({
    context_uri: albumUri,
  });

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      if (res.statusCode === 204) {
        resolve();
      } else {
        reject(new Error(`Error playing album. Status code: ${res.statusCode}`));
      }
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.write(data);
    req.end();
  });
}

// Helper function: Wait for a specified duration
function wait(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

// Create a server to handle the callback
http.createServer(async (req, res) => {
  const requestUrl = url.parse(req.url, true);
  const code = requestUrl.query.code;

  if (code) {
    const tokens = await getTokens(code);

    // Replace the following console.log with your desired actions
    console.log('Access Token:', tokens.access_token);
    console.log('Refresh Token:', tokens.refresh_token);

    // Call the example function to run the code
    await exampleUsage(tokens.access_token);

    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Authentication successful! You can close this page now.');
  } else {
    res.statusCode = 400;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Authorization code not found in the callback URL.');
  }
}).listen(3000, () => {
  console.log('Server listening on http://localhost:3000');
});

// Call the authorize function to start the login flow
authorize();

 

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

14 Replies

You can not use that endpoint and scopes with 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.

What do you mean? Using server I want to connect to server of Spotify and play some music, how can I do that?

Client Credentials Flow: "Since this flow does not include authorization, only endpoints that do not access user information can be accessed."

You should implement the Authorization Code Flow.
Edit: or the Authorization code with PKCE extension, or the Implicit grant.

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.

But it requires a code, that I don't have and also a redirect_url which I have no idea why should I use it

I mean that in my app I can't use redirect_url, because there is no interacting with the browser, because I don't need it in my app

Then you can't make your app work.

It definitely won't work with 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.

Then how can I contact developers of Spotify, so that they could tell me what to do?

Everything you'll need is already documented:

https://developer.spotify.com/documentation/web-api/concepts/authorization

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, client credentials is what I need, no?

No, one of these:

Because you'll need to Access User Resources.

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.

And which one can I use fully on server side?

You can use the Authorization code for this, but you'll need to be able to log in once to get an access token and refresh token. Then, the sever can use the refresh token to get a new access token and refresh token when they are expired. If it doesn't get a new refresh token, it can keep using the old one.

 

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.

And how should I make an redirect_url? I even don't have framework such as express in my application ( which means I can't use redirect_url )

Marked as solution

Here's an example Node.js app, without the need for installing any modules. You have to be able to see the console on your server, though.

const http = require('http');
const url = require('url');
const querystring = require('querystring');
const https = require('https');

const clientId = 'YOUR_CLIENT_ID';
const clientSecret = 'YOUR_CLIENT_SECRET';
const redirectUri = 'http://localhost:3000/callback';
const scopes = ['user-modify-playback-state', 'user-top-read', 'user-read-playback-state'];

// Step 1: Get authorization code
function authorize() {
  const authorizeUrl = 'https://accounts.spotify.com/authorize';
  const queryParams = querystring.stringify({
    response_type: 'code',
    client_id: clientId,
    scope: scopes.join(' '),
    redirect_uri: redirectUri,
  });
  const authorizationUrl = `${authorizeUrl}?${queryParams}`;
  console.log(`Please authorize the application by visiting this URL: ${authorizationUrl}`);
}

// Step 2: Get access and refresh tokens
async function getTokens(authorizationCode) {
  const tokenUrl = 'https://accounts.spotify.com/api/token';
  const data = querystring.stringify({
    grant_type: 'authorization_code',
    code: authorizationCode,
    redirect_uri: redirectUri,
  });
  const authHeader = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');

  const options = {
    hostname: 'accounts.spotify.com',
    path: '/api/token',
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Authorization: `Basic ${authHeader}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data));
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.write(data);
    req.end();
  });
}

// Step 3: Refresh access token
async function refreshAccessToken(refreshToken) {
  const tokenUrl = 'https://accounts.spotify.com/api/token';
  const data = querystring.stringify({
    grant_type: 'refresh_token',
    refresh_token: refreshToken,
  });
  const authHeader = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');

  const options = {
    hostname: 'accounts.spotify.com',
    path: '/api/token',
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Authorization: `Basic ${authHeader}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data));
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.write(data);
    req.end();
  });
}

// Step 4: Example usage
async function exampleUsage(accessToken) {
  // Get the user's top tracks
  const topTracks = await getTopTracks(accessToken);

  if (topTracks.length === 0) {
    console.log('No top tracks found.');
    return;
  }

  // Retrieve the album of the first top track
  const topTrack = topTracks[0];
  const album = await getAlbum(accessToken, topTrack.album.id);

  if (!album) {
    console.log('No album found.');
    return;
  }

  // Get the user's available devices
  const devices = await getAvailableDevices(accessToken);

  if (devices.length === 0) {
    console.log('No devices found.');
    return;
  }

  // Retrieve the device ID of the first available device
  const deviceId = devices[0].id;

  // Play the album on the first available device
  await playAlbum(accessToken, deviceId, album.uri);

  console.log(`Playing album "${album.name}" by ${album.artists[0].name}`);
}

// Example function: Get the user's top tracks
async function getTopTracks(accessToken) {
  const topTracksUrl = 'https://api.spotify.com/v1/me/top/tracks';

  const options = {
    hostname: 'api.spotify.com',
    path: '/v1/me/top/tracks',
    method: 'GET',
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data).items);
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.end();
  });
}

// Example function: Get album details
async function getAlbum(accessToken, albumId) {
  const albumUrl = `https://api.spotify.com/v1/albums/${albumId}`;

  const options = {
    hostname: 'api.spotify.com',
    path: `/v1/albums/${albumId}`,
    method: 'GET',
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data));
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.end();
  });
}

// Example function: Get available devices
async function getAvailableDevices(accessToken) {
  const devicesUrl = 'https://api.spotify.com/v1/me/player/devices';

  const options = {
    hostname: 'api.spotify.com',
    path: '/v1/me/player/devices',
    method: 'GET',
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        resolve(JSON.parse(data).devices);
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.end();
  });
}

// Example function: Play album on device
async function playAlbum(accessToken, deviceId, albumUri) {
  const playbackUrl = `https://api.spotify.com/v1/me/player/play?device_id=${deviceId}`;

  const options = {
    hostname: 'api.spotify.com',
    path: `/v1/me/player/play?device_id=${deviceId}`,
    method: 'PUT',
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
  };

  const data = JSON.stringify({
    context_uri: albumUri,
  });

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      if (res.statusCode === 204) {
        resolve();
      } else {
        reject(new Error(`Error playing album. Status code: ${res.statusCode}`));
      }
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.write(data);
    req.end();
  });
}

// Helper function: Wait for a specified duration
function wait(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

// Create a server to handle the callback
http.createServer(async (req, res) => {
  const requestUrl = url.parse(req.url, true);
  const code = requestUrl.query.code;

  if (code) {
    const tokens = await getTokens(code);

    // Replace the following console.log with your desired actions
    console.log('Access Token:', tokens.access_token);
    console.log('Refresh Token:', tokens.refresh_token);

    // Call the example function to run the code
    await exampleUsage(tokens.access_token);

    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Authentication successful! You can close this page now.');
  } else {
    res.statusCode = 400;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Authorization code not found in the callback URL.');
  }
}).listen(3000, () => {
  console.log('Server listening on http://localhost:3000');
});

// Call the authorize function to start the login flow
authorize();

 

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.

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