Search code examples
node.jsexpresscorsxmlhttprequestspotify

Enabling CORS not working with Spotify Web API


I'm building an Express application that uses the Spotify Web API and I'm using ejs as my view engine. I have one ejs page where you click a button and it calls an endpoint in my Express server which redirects a few times (within the same server) using res.redirect() before finally landing on an endpoint that calls https://accounts.spotify.com/authorize like this

res.redirect('https://accounts.spotify.com/authorize' +
      '?response_type=code' +
      '&client_id=' + process.env.SPOTIFY_CLIENT_ID +
      (scopes ? '&scope=' + encodeURIComponent(scopes) : '') +
      '&redirect_uri=' + encodeURIComponent(process.env.SPOTIFY_REDIRECT_URI))

However, in my browser's inspect window, this is the error I get:

Access to XMLHttpRequest at 'https://accounts.spotify.com/authorize?{my params here}' (redirected from 'http://localhost:5000/login') from origin 'http://localhost:5000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

When I make the original call from my ejs page, I use the XMLHttpRequest library and I make the request like so:

xhttp.open("POST", "http://localhost:5000/login", true)
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
xhttp.setRequestHeader('Access-Control-Allow-Origin', '*')
xhttp.setRequestHeader('Access-Control-Allow-Method', 'GET, POST, PATCH, PUT, DELETE, OPTIONS')
xhttp.setRequestHeader('Access-Control-Allow-Headers', 'Origin, Content-Type, X-Auth-Token')
xhttp.send(`email=${email}&password=${password}`)

I also use the CORS package on my server side code like so:

app.use(cors())

Do I need to enable CORS somewhere else or is there something else that I'm missing completely?


Solution

  • 1) You don't have to send Access-Control-* headers when making call from your client (ejs page).

    2) The server needs to respond back with Access-Control-* headers to allow CORS. The server also needs to handle 'OPTIONS' request first. Normally, I do this without using the cors middleware like this:

    // Enabling CORS
    app.use((req, res, next) => {
      res.header("Access-Control-Allow-Origin", "*");
      res.header("Access-Control-Allow-Headers", "*");
    
      if (req.method === "OPTIONS") {
        res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH");
        return res.status(200).json({});
      }
      next();
    });
    

    It's not a good practice to use * and it will not be allowed in the case where browser needs to accept cookies. But you can use it now to test your api.

    The above can also be achieved using cors middleware. The below line:

    app.use(cors())
    

    should be added only once before the request is sent to any route/controller. This ensures that the headers required to allow CORS are actually added for every response.

    Update: If you want to access the spotify page from your browser, it should be redirected from your client (ejs page). Get the necessary data from your server and use it to redirect from your client.