3 Ways To Fix The CORS Error - and How The Access-Control-Allow-Origin Header Works

Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

3 Ways to Fix the CORS Error — and

How the Access-Control-Allow-Origin


Header Works
David Katz
Jan 29 · 7 min read

The Cors Error

Seen this before? Seeing it right now?

When working with APIs in your application code, honestly, this bug creeps up more
often than it should. And every time, the reaction is the same:
Fix one: install the Allow-Control-Allow-Origin plugin
The quickest fix you can make is to install the moesif CORS extension . Once installed,
click it in your browser to activate the extension. Make sure the icon’s label goes from
“off”:

to “on”:

Then refresh your application, and your API requests should now work!

But the plugin fix is deceiving


The plugin definitely addresses the issue. However, this fix only applies to your own
machine. In local development, it’s fine to have a plugin installed that can help you get
past the error.

But once you publish your application, you can’t expect your users to install the plugin
too. It wouldn’t be the wisest business decision…

There’s gotta be better solutions. To get there, let’s answer a couple questions:

Why was the CORS error there in the first place?


The error stems from a security mechanism that browsers implement called the same-
origin policy.

The same-origin policy fights one of the most common cyber attacks out there: cross-
site request forgery. In this maneuver, a malicious website attempts to take advantage
of the browser’s cookie storage system.

For every HTTP request to a domain, the browser attaches any HTTP cookies associated
with that domain. This is especially useful for authentication, and setting sessions. For
instance, it’s feasible that you would sign into a web app like facebook-clone.com. In
this case, your browser would store a relevant session cookie for the facebook-
clone.com domain:

And this is great! The session cookie gets stored. And every time you re-visit the
facebook-clone.com tab, and click around the app, you don’t have to sign in again.
Instead, the API will recognize the stored session cookie upon further HTTP requests.

The only trouble is that the browser automatically includes any relevant cookies stored
for a domain when another request is made to that exact domain. Therefore, a scenario
like this can happen. Say you clicked on a particularly trick popup add, opening evil-
site.com.

The evil site also has the ability send a request to facebook-clone.com/api. Since the
request is going to the facebook-clone.com domain, the browser includes the relevant
cookies. Evil-site sends the session cookie, and gains authenticated access to facebook-
clone. Your account has been successfully hacked with a cross-site request forgery
attack.

Luckily, in this situation, like a hawk ready to strike, the browser will step in and
prevent the malicious code from making an API request like this. It will stop evil-site
and say “Blocked by the same-origin policy. ”
How does the same-origin policy work under the hood?
Under the hood, the browser checks if the origins of the web application and the server
match. Above, the origins were simplified to the frontend application and backend
server domains. But really, the origin is the combination of the protocol, host, and port.
For example, in https://www,facebook-clone.com, the protocol is https://, the host is
www.facebook-clone.com, and the hidden port number is 443 (the port number
typically used for https).

To conduct the same-origin check, the browser accompanies all requests with a special
request that sends the domain information receiving server. For example, for an app
running on localhost:3000, the special request format looks like this:

Origin: http://localhost:3000

Reacting to this special request, the server sends back a response header. This header
contains an Access-Control-Allow-Origin key, to specify which origins can access the
server’s resources. The key will have one of two values:

One: the server can be really strict, and specify that only one origin can access it:

Access-Control-Allow-Origin: http://localhost:3000

Two: the server can let the gates go wide open, and specify the wildcard value to allow
all domains to access its resources:

Access-Control-Allow-Origin: *

Once the browser receives this header information back, it compares the frontend
domain with the Access-Control-Allow-Origin value from the server. If the frontend
domain does not match the value, the browser raises the red flag and blocks the API
request with the CORS policy error.

Did the plugin “fix” it?


In short, no. The access-control-allow-origin plugin essentially turns off the browser’s
same-origin policy. For every request, it will add the Access-Control-Allow-Origin: *

header to the response. It tricks the browser, and overrides the CORS header that the
server has in place with the open wildcard value.

Now, it’s fine to leave this plugin on in local development. It’s possible that you already
know that the server specifies the Access-Control-Allow-Origin header as the
published frontend domain for your app. Then by all means, use the plugin in
development to allow the localhost domain to make requests within the browser.

But if you’re consuming another API, the plugin hasn’t “fixed” the issue. As mentioned
before, you wouldn’t want to demand that your users install a plugin to access your
code.

Fix two: send your request to a proxy


You can’t ask your users to trick their browsers by installing a plugin that applies an
header in the frontend. But you can control the backend address that the web app’s API
requests are going to.

The cors-anywhere server is a proxy that adds CORS headers to a request. A proxy acts
as an intermediary between a client and server. In this case, the cors-anywhere proxy
server operates in between the frontend web app making the request, and the server
that responds with data. Similar to the Allow-control-allow-origin plugin, it adds the
more open Access-Control-Allow-Origin: * header to the response.

It works like this. Say your frontend is trying to make a GET request to:

https://joke-api-strict-cors.appspot.com/jokes/random

But this api does not have a Access-Control-Allow-Origin value in place that permits
the web application domain to access it. So instead, send your GET request to:

https://cors-anywhere.herokuapp.com/https://joke-api-strict-

cors.appspot.com/jokes/random

The proxy server receives the https://joke-api-strict-cors.appspot.com/jokes/random

from the url above. Then it makes the request to get that server’s response. And finally,
the proxy applies the Access-Control-Allow-Origin: * to that original response.
This solution is great because it works in both development and production. In
summary, you’re taking advantage of the fact that the same origin policy is only
implemented in browser-to-server communication. Which means it doesn’t have to be
enforced in server-to-server communication!

The one downside of the cors-anywhere proxy is that can often take a while to receive a
response. The latency is high enough to make your applications appear a bit sluggish.

This brings us to a final, even better approach.

Fix three: build your own proxy


The fix I recommend in situations like this, is to build your own proxy! Exactly like the
previous solution, you’re utilizing the fact that the same origin policy is not enforced
within server-to-server communication. In addition, you eliminate the latency concern.
You don’t need to share the cors-anywhere proxy with other consumers, and you can
dedicate as many resources as you need to your own servers.

Here’s some quick Node.js code that uses the express web framework to create a proxy
server around the same https://joke-api-strict-cors.appspot.com/ from above:

1 const express = require('express');


2 const request = require('request');
3
4 const app = express();
5
6 app.use((req, res, next) => {
7 res.header('Access-Control-Allow-Origin', '*');
8 next();
9 });
10
11 app.get('/jokes/random', (req, res) => {
12 request(
13 { url: 'https://joke-api-strict-cors.appspot.com/jokes/random' },
14 (error, response, body) => {
15 if (error || response.statusCode !== 200) {
16 return res.status(500).json({ type: 'error', message: err.message });
17 }
18
19 res.json(JSON.parse(body));
20 }
21 )
22 });
23
23
24 const PORT = process.env.PORT || 3000;
25 app.listen(PORT, () => console.log(`listening on ${PORT}`));

express-cors-proxy-server.example.js hosted with ❤ by GitHub view raw


If you want to see this in action, head to the source code for the above, along with relevant steps in the
README: https://github.com/15Dkatz/beat-cors-server

How does this work? The proxy uses express middleware to apply a Access-Control-

Allow-Origin: * header to every response from the server. At its own jokes/random

GET endpoint, the proxy requests a random joke from another server. The same-origin
policy doesn’t step in to block the request, even though the domains are different. After
all, this is a server-to-server request. Finally, the proxy creates a response to the original
requester (an app on the browser) consisting of the resulting data and the middleware-
applied Access-Control-Allow-Origin: * header.

Conclusion
The CORS error can be the bane of the frontend developer. But once you understand
the underlying same-origin policy behind the error, and how it fights the malicious
cross-site request forgery attack, it becomes a little more bearable.

Ultimately, with these fixes, you’ll never have to break a sweat over seeing that red
CORS error in your browser console logs again. Instead, in its face, you’ll whip out the
plugin or a proxy, and exclaim:

Connect with David


If you enjoyed this content, check out David’s website at https://davidtkatz.com where
you can find links to reach out and connect with him.

Also, David has published 15 coding courses with 180,000 students from 192 countries
around the world. His latest one teaches React and Redux, in full bootcamp style! Since
you’re here from Medium, feel free use the special Medium discount to access the full
course: https://www.udemy.com/react-redux-bootcamp/?
couponCode=FROMMEDIUM

Cors Same Origin Policy Nodejs Express Http Request

About Help Legal

You might also like