CORS error when connecting React app to Spotify API authentication

I’m having trouble with Spotify API authentication in my React application

I’m pretty new to React and Express.js development. I’m building an app that needs to connect to Spotify’s Web API to get user data. I found some example code online that worked perfectly when using a simple HTML page with buttons, but now I’m trying to integrate it into my React frontend and I keep running into CORS issues.

When I try to make the authentication request from my React component, I get this CORS error message:

Access to XMLHttpRequest at 'https://accounts.spotify.com/authorize?response_type=code&client_id=...' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

My React component code:

import React from 'react';
import './SpotifyAuth.scss';
import axios from 'axios';

export default class SpotifyLogin extends React.Component {
  authenticateUser() {
    axios
      .get('http://localhost:9000/authenticate', {
        headers: {
          'Access-Control-Allow-Origin': '*',
        }
      })
      .then(response => {
        console.log('Success:', response);
      })
      .catch(error => {
        console.error('Authentication failed:', error);
      });
  }

  render() {
    return (
      <div className="auth-container">
        <div className="content">
          <div className="header"><h2>Music Player</h2></div>
          <button 
            className="auth-button" 
            type="button" 
            onClick={() => this.authenticateUser()}>
            Connect to Spotify
          </button>
        </div>
      </div>
    );
  }
}

My Express server code:

const express = require('express');
const request = require('request');
const cors = require('cors');
const querystring = require('querystring');
const cookieParser = require('cookie-parser');
const SpotifyAPI = require('spotify-web-api-node');

const server = express();

server.use(express.json());
server.use(express.urlencoded({ extended: true }));
server.use(cors());
server.use(cookieParser());

let currentUserId = '';
const authStateKey = 'auth_state_spotify';

const appClientId = 'your_client_id_here';
const appClientSecret = 'your_client_secret_here';
const callbackURL = 'http://localhost:9000/auth-callback';

const spotifyClient = new SpotifyAPI({
  clientId: appClientId,
  clientSecret: appClientSecret,
  redirectUri: callbackURL
});

function createRandomString(len) {
  let result = '';
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  
  for (let i = 0; i < len; i++) {
    result += characters.charAt(Math.floor(Math.random() * characters.length));
  }
  return result;
}

server.get('/authenticate', function(req, res) {
  const randomState = createRandomString(16);
  res.cookie(authStateKey, randomState);

  const permissions = 'user-read-private user-read-email';
  res.redirect('https://accounts.spotify.com/authorize?' +
    querystring.stringify({
      response_type: 'code',
      client_id: appClientId,
      scope: permissions,
      redirect_uri: callbackURL,
      state: randomState
    }));
});

server.get('/auth-callback', function(req, res) {
  const authCode = req.query.code || null;
  const stateParam = req.query.state || null;
  const savedState = req.cookies ? req.cookies[authStateKey] : null;

  if (stateParam === null || stateParam !== savedState) {
    res.redirect('/#' + querystring.stringify({ error: 'state_mismatch' }));
  } else {
    res.clearCookie(authStateKey);
    
    const tokenRequest = {
      url: 'https://accounts.spotify.com/api/token',
      form: {
        code: authCode,
        redirect_uri: callbackURL,
        grant_type: 'authorization_code'
      },
      headers: {
        'Authorization': 'Basic ' + Buffer.from(appClientId + ':' + appClientSecret).toString('base64')
      },
      json: true
    };

    request.post(tokenRequest, function(err, response, data) {
      if (!err && response.statusCode === 200) {
        const userToken = data.access_token;
        const refreshToken = data.refresh_token;
        
        spotifyClient.setAccessToken(userToken);

        const userDataRequest = {
          url: 'https://api.spotify.com/v1/me',
          headers: { 'Authorization': 'Bearer ' + userToken },
          json: true
        };

        request.get(userDataRequest, function(err, response, userData) {
          console.log('User data:', userData);
          currentUserId = userData.id;
        });

        res.redirect('/#' + querystring.stringify({
          access_token: userToken,
          refresh_token: refreshToken
        }));
      } else {
        res.redirect('/#' + querystring.stringify({ error: 'invalid_token' }));
      }
    });
  }
});

server.listen(9000, () => {
  console.log('Server running on port 9000');
});

I have CORS enabled on my Express server but I’m still getting this error. How can I fix this issue and make the authentication work properly from my React app?

dont use axios for the auth redirect, you need to use window.location.href instead since spotify auth requires a full page redirect not an ajax call. change your authenticateUser function to just do window.location.href = 'http://localhost:9000/authenticate' and it should work fine.

The issue here is that you’re treating OAuth authentication like a regular API call. Spotify’s authorization flow is designed to work with browser redirects, not XMLHttpRequests or axios calls. When you use axios, the browser tries to make a preflight OPTIONS request which fails because Spotify doesn’t expect AJAX calls to their authorization endpoint.

I ran into this exact problem when I first started working with OAuth APIs. The solution is to handle the authentication redirect on your server side and then redirect the user’s browser directly. Your Express route is already set up correctly for this - it uses res.redirect() which is the right approach.

Instead of calling your authenticate endpoint with axios, you should either redirect the user directly to your server endpoint or build the Spotify authorization URL in your React component and redirect there. The authentication flow needs to happen in the main browser window, not through an AJAX request, because Spotify needs to show their login page and then redirect back to your callback.