Javascript Cross-Origins CORS Fetch (Simple Example)

Welcome to a quick tutorial and example on how to perform a cross-origin fetch request in Javascript. Are you trying to do a fetch request to a different domain? Only to be denied with a “no Access-Control-Allow-Origin header is present” error?

To perform a cross-origin fetch call:

  1. On the first site, do a fetch call to the second site – fetch("http://second.com/page.php", { mode : "cors" });
  2. Allow cross-origin on the second site.
    • header("Access-Control-Allow-Origin: http://first.com");
    • // SCRIPT AS USUAL

Yes, it’s that simple. But let us walk through more details on CORS and how to set up virtual hosts on localhost (with XAMPP) for testing – Read on!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TLDR – QUICK SLIDES

 

TABLE OF CONTENTS

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

 

WHAT IS CORS?

Before we get into the code example, let us answer the million-dollar question – What the heck is “CORS”?

 

CROSS-ORIGIN RESOURCE SHARING

Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. MDN

In simple terms, making a request from your website http://first.com to another website http://second.com.

 

WHY IS CROSS-ORIGIN NOT ALLOWED BY DEFAULT!?

One word – Security. Imagine a world with no restrictions.

  • Anyone can submit forms to whatever site they please. Send data to whoever they like. There is no control, no verification.
  • Anyone can masquerade a request to delete accounts on other websites. Or even process transactions on another website.

Yep, it’s pure chaos. So the “default rule” is that http://second.com will only accept and process requests from http://second.com; All requests from http://first.com to http://second.com will be ignored.

 

ALLOW ORIGIN & CREDENTIALS

  • When we fire fetch("http://second.com") on http://first.com, this will send a HTTP header of Origin: http://first.com.
  • To accept the cross-origin call, http://second.com needs to respond with the HTTP header – Access-Control-Allow-Origin: http://first.com.
  • That pretty much seals the deal. If you want to also send cookies and credentials from first.com to second.com – Access-Control-Allow-Credentials: true.

P.S. For the “exact mechanics”, this post on Javascript.info gives a good breakdown of the exchange.

 

 

CORS FETCH WITH XAMPP

With that, let us now get into the example of setting up virtual hosts and running a CORS fetch. All on a local machine.

 

STEP 1) UPDATE THE HOSTS FILE

C:\Windows\System32\drivers\etc\hosts
127.0.0.1 site-a.com
127.0.0.1 site-b.com

For the uninitiated – Don’t need to panic, all that is happening here is a manual DNS override. That is, http://site-a.com and http://site-b.com will now resolve to localhost 127.0.0.1. If you are using IPV6, change it to ::1 instead.

P.S. Mac and Linux users, your hosts file is probably located at /etc/hosts. Although that may differ for different builds and versions.

 

STEP 2) APACHE VIRTUAL HOST

xampp\apache\conf\extra\httpd-vhosts.conf
# SITE-A.COM
<VirtualHost *>
  DocumentRoot "C:/sitea/"
  ServerName site-a.com
  <Directory "C:/sitea/">
    Options Indexes FollowSymLinks Includes ExecCGI
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>
 
# SITE-B.COM
<VirtualHost *>
  DocumentRoot "C:/siteb/"
  ServerName site-b.com
  <Directory "C:/siteb/">
    Options Indexes FollowSymLinks Includes ExecCGI
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>
  • Next, we need to create 2 folders – sitea/ and siteb/.
  • Edit httpd-vhosts.conf, create two virtual hosts for site-a.com and site-b.com – Map them to the respective sitea/ and siteb/ folder.

 

 

STEP 3) CROSS-ORIGIN FETCH REQUEST

sitea/fetch.html
<script>
function fetchCORS () {
  fetch("http://site-b.com/cors.php", {
    mode : "cors",
    credentials : "include"
  })
  .then(res => { return res.text(); })
  .then(txt => { console.log(txt); })
  .catch(err => { console.error(err); });
}
</script>
<input type="button" value="Fetch Request" onclick="fetchCORS()">

Now that the virtual hosts are ready, let us create a simple HTML page to fire a cross-origin fetch request.

P.S. It is already mode : "cors" by default in modern browsers. This is probably “extra”, but we still define it as “to be safe”.

P.P.S. With credentials : "include", the fetch request will also send cookies and credentials. If you don’t want this to happen, set credentials : "omit" instead.

 

STEP 4) CROSS-ORIGIN ALLOW

4A) LAZY CROSS-ORIGIN ALLOW

siteb/cors.php
<?php
// (A) THE LAZY WAY
header("Access-Control-Allow-Origin: *");
echo "It works!";

The lazy way to respond to cross-origin calls is to reply with Access-Control-Allow-Origin: *. Yes, this works, but take note:

  • Any website can call this script, it is more vulnerable to attacks.
  • With Allow-Origin: *, we cannot set Allow-Credentials: true; We cannot send cookies and credentials this way.

 

4B) BETTER CROSS-ORIGIN ALLOW

siteb/cors.php
<?php
// (B) SMARTER WAY
// (B1) GET REQUEST ORIGIN
if (array_key_exists("HTTP_ORIGIN", $_SERVER)) {
  $origin = $_SERVER["HTTP_ORIGIN"];
} else if (array_key_exists("HTTP_REFERER", $_SERVER)) {
  $origin = $_SERVER["HTTP_REFERER"];
} else {
  $origin = $_SERVER["REMOTE_ADDR"];
}
 
// (B2) ALLOWED DOMAINS
if (!in_array(
  parse_url($origin, PHP_URL_HOST),
  ["localhost", "site-a.com", "site-b.com"]
)) {
  http_response_code(403);
  exit("$origin not allowed");
}
 
// (B3) PROCEED
header("Access-Control-Allow-Origin: $origin");
header("Access-Control-Allow-Credentials: true");
echo "It works!";

This is a slightly smarter and safer way to deal with cross-domain calls. We counter-check the origin of the request, and respond only if it is an “allowed domain”. While this is not 100% foolproof, it will not respond to everyone at the very least.

 

 

EXTRA BITS & LINKS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

COMPATIBILITY CHECKS

Fetch is already well-supported across all modern browsers at the time of writing. But if you have to support legacy browsers – It is also possible to set CORS in XMLHttpRequest.

 

LINKS & REFERENCES

 

INFOGRAPHIC CHEATSHEET

CORS Fetch With XAMPP (Click To Enlarge)

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

Leave a Comment

Your email address will not be published.