A JavaScript application running in the browser can only access some HTTP resources on the same origin (domain, port and protocol) that serves it.

Loading images or scripts/styles always works even if cross-origin, but XHR and Fetch calls to another server will fail.

ES Modules also follow this convention. Also loading Web Fonts using @font-face has same-origin policy by default, and other like WebGL textures and drawImage resources loaded in the Canvas API are limited by this convention.

All this happens for security reasons, unless that server implements a way to allow that connection.

This way is called CORS, Cross-Origin Resource Sharing.

If you don’t set up a CORS policy on the server that allows to serve 3rd party origins, the request will fail.

Fetch example:

Fetch failed because of CORS policy

XHR example:

XHR request failed because of CORS policy

A Cross-Origin resource fails if it’s:

  • to a different domain
  • to a different subdomain
  • to a different port
  • to a different protocol

and it’s there for your security, to prevent malicious users to exploit the Web Platform.

All browsers support CORS, except older versions of IE, which only implemented it in version 10:

CORS browser support

But if you control both the server and the client, you have all the good reasons to allow them to talk to each other.

How? It depends on your server-side stack. This is not a Node.js course but since we are talking about JavaScript I’ll introduce a simple Node.js CORS-enabled Web Server with Express.

A CORS implementation with Express

If you are using Node.js and Express as a framework, use the CORS middleware package.

Here’s a simple implementation of an Express Node.js server:

const express = require('express')
const app = express()

app.get('/without-cors', (req, res, next) => {
  res.json({ msg: '😞 no CORS, no party!' })
})

const server = app.listen(3000, () => {
  console.log('Listening on port %s', server.address().port)
})

If you hit /without-cors with a fetch request from a different origin, it’s going to raise the CORS issue.

All you need to do to make things work out is to require the cors package linked above, and pass it in as a middleware function to an endpoint request handler:

const express = require('express')
const cors = require('cors')
const app = express()

app.get('/with-cors', cors(), (req, res, next) => {
  res.json({ msg: 'WHOAH with CORS it works! 🔝 🎉' })
})

/* the rest of the app */

I made a simple Glitch example. Here is the client working, and here’s its code: https://glitch.com/edit/#!/flavio-cors-client.

This is the Node.js Express server: https://glitch.com/edit/#!/flaviocopes-cors-example-express

Note how the request that fails because it does not handle the CORS headings correctly is still received, as you can see in the Network panel, where you find the message the server sent:

No response from CORS

Allow only specific origins

This example has a problem however: ANY request will be accepted by the server as cross-origin.

As you can see in the Network panel, the request that passed has a response header access-control-allow-origin: *:

The CORS response header

You need to configure the server to only allow one origin to serve, and block all the others.

Using the same cors Node library, here’s how you would do it:

const cors = require('cors')

const corsOptions = {
  origin: 'https://yourdomain.com'
}

app.get('/products/:id', cors(corsOptions), (req, res, next) => {
  //...
})

Video