Eliminate CORS Policy Errors on a Frontend Application
Tags: javascript, react, webdev, node
Published: 2022-10-10 10:44:29

You just signed up for an API service and have been provided with your unique API key to work with. You've tested calls to the endpoints with Postman or VSCode's Thunder Client extension, and everything seems to work fine. Now, it's time to incorporate this in your frontend application, and you get hit with an unexpected error from your browser console: 
![CORS error message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bury44eq94l55bh1bsm9.png)

This error on the browser can be a real pain when working with APIs, especially for a new developer. This article provides a clear understanding of what CORS policy errors are and shows ways to avoid them when developing applications. 

---

## Understanding the error 
Cross-Origin Resource Sharing (CORS) is a mechanism that allows a server to control which domains (or origins) outside its own from which a browser may allow resource requests. This mechanism is implemented in line with the *same-origin policy* — a security model whereby a browser can permit scripts in a document or webpage to interact with resources from another webpage only if both web pages are of the same origin. An advantage of this is that it combats malicious attacks by preventing scripts on one page from accessing sensitive information on another page and relaying this data to the attacker. 

> Two URLs have the same origin if the protocol, port (if specified), and host are the same for both.

CORS serves as a way to relax a browser's same-origin policy by allowing cross-origin requests from subdomains and trusted third parties. When a request is made from a browser to an API endpoint, the browser sends a preflight request to its server looking for permissions. The preflight request precedes the actual request to the endpoint and checks whether or not this request will be allowed by the server. It contains information about the actual request, such as HTTP headers and methods, and determines if the browser should send the actual request by assessing the response from the server.

 A CORS policy error like the image above is returned as a response to the preflight request sent by the browser stating that one of the required HTTP request headers — `Access-Control-Allow-Origin` — is missing. So, how do we fix this?

---


## Finding a solution
There are several ways to fix CORS policy errors encountered in an application. The quickest of these is to install a browser extension that includes the `Access-Control-Allow-Origin` option to the request header. There are extensions available in the [Chrome Web Store](https://chrome.google.com/webstore/search/CORS) that allow browsers to perform seamless cross-domain requests in a web application when enabled. However, it is misleading to solve CORS errors this way because the extension merely tricks the browser into thinking the `Access-Control-Allow-Origin` header is included in the request when that is not the case. Hence, the extension only fixes the issue while enabled on _your_ browser. 



### Fixing CORS errors the right way
Since the solution described above only temporarily fixes the CORS error by including the missing request header, it is not a recommended fix because this request header remains missing on browsers without the extension, leading to the same errors. Another way to fix CORS errors is to send all requests to the endpoint through a _proxy server_. The proxy acts as an intermediary server between the client and the endpoint server and includes the `Access-Control-Allow-Origin` header on all requests to the endpoint. When a request is made from a browser to the API endpoint, the browser immediately sends the request to the proxy server. The proxy server adds the CORS headers to the request and then forwards it to the actual endpoint server.

There are a few free CORS proxies available for use on the internet. However, it is not advisable to use these proxies on production applications due to security, speed, and performance concerns. A more commonly used and accepted alternative is to build an application's proxy from scratch. Building your proxy offers the same benefits as the free CORS proxies while also eliminating the security and latency concerns associated with them. In this article, you will learn how to create your own proxy server to fix CORS policy errors.

---

## Requirements
In this section, I will show you all the steps and installations required to build this in your application. To follow along with the rest of this guide, you will need the following: 

- [Node](https://nodejs.org/en/download/) and `npm` enabled on your device.
- An API resource that restricts cross-origin HTTP requests. For this guide, I'll be using the CoinMarketCap API. 
- A frontend application with `npm` initialized.

If you do not have `npm` on your project, you must initialize it by running the command below at the root of your project's directory: 

```shell
npm init
```
This command creates a project scaffold with the `package.json` file that contains our project's dependencies. Next, we need to download some packages to enable us to create the proxy server and make requests from it. These packages are: 
- **[express](https://www.npmjs.com/package/express/):** This is a minimalistic back-end web application framework for Node.js.
- **[cors](https://www.npmjs.com/package/cors/):** A Node.js package that enables CORS in an Express middleware.
- **[axios](https://www.npmjs.com/package/axios/):** This is a promise-based HTTP client for Node.js. This is my preferred choice for making requests but feel free to use any alternative you desire. 

All required packages are available on the `npm` package registry. To download them to your project, run the command below at the root of your project's directory:

```shell
npm i express cors axios
```
---

## Getting started
Before we begin building our proxy, let's take a look at the current request we're making to the endpoint from our application. 
```javascript
  const options = {
   method: "GET",
   url: "https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest",
   headers: {
      "X-CMC_PRO_API_KEY": process.env.REACT_APP_MARKET_CAP_KEY,
    },
   params: {
     slug: "bitcoin,ethereum,band-protocol,tezos",
    },
  };

  Axios.request(options)
    .then((response) => {
      console.log(response.data);
    })
    .catch((error) => {
      console.log(error);
    });
```

The snippet above makes a client-side request with JavaScript from our frontend application. Certain API providers — like ours — tend to block requests of this nature for several reasons, usually to protect their users' API keys since they can still be accessed on the browser. This request returns an error that we can view in the "Console" tab of the browser's Developer Tools.

![CORS error on browser console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hhfmtgcx6kipx3cdhb5c.png)

Now, let's start creating our proxy server. Begin by creating a new file named `index.js` in your project's root directory. This file will contain all the Node.js code for the server. Next, paste the following code in the `index.js` file created:
```js
const PORT = 8080;
const express = require("express");
const cors = require("cors");
const axios = require("axios");

require("dotenv").config();

const app = express();

app.use(cors());

app.get("/", (req, res) => {
  const options = {
    method: "GET",
    url: "https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest",
    headers: {
      "X-CMC_PRO_API_KEY": process.env.REACT_APP_MARKET_CAP_KEY,
    },
    params: {
      slug: "bitcoin,ethereum,band-protocol,tezos",
    },
  };

  axios
    .request(options)
    .then((response) => {
      res.json(response.data);
    })
    .catch((error) => {
      res.json(error);
    });
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
```
Let's go over the code above, shall we?
- First, we define a port for the server to run on our local machine. Ours is set to port `8080`.
- Next, we bring in all the required modules and assign them to constants. 
```javascript
require("dotenv").config();
```
- The line above is required to load environment variables defined in a `.env` file. To use this in your application, you must install the [dotenv](https://www.npmjs.com/package/dotenv) module as seen on the `npm` registry.

- Next, we initialize the express package and assign it to a constant called `app`. Then, we enable all CORS requests by calling the `cors` package inside the `app.use` method.
- Below that, we make an HTTP request similar to our previous client-side request inside the `app.get` method. This method lets us define a route handler for `GET` requests. Ours is set to the root route —`/`— in the snippet above.
- Lastly, the `app.listen` method is used to bind and listen for connections on the specified port — `http://localhost:8080/`.

Now that we have the server setup, we must create a start script for starting the server. Go to the `package.json` file at the root of your project directory and add the line below to the `scripts` object:
```json
"start:backend": "node index.js",
```
This defines the start script for running the server locally. Depending on your original setup, your `package.json` file should look something like this: 
```json
{  
  "name": "project_name",  
  "description": "project_description",  
  "scripts": {  
    "start": "react-scripts start",
    "start:backend": "node index.js"
  },  
  "dependencies": {
    "axios": "^0.21.0",
    "cors": "^2.8.5",
    "dotenv": "^16.0.1",
    "express": "^4.18.1"
  }
}   
```
Notice all the installed packages listed as _dependencies_. Also, notice there are separate start scripts for the frontend and backend to prevent any confusion.

To start up the server, run the command below in your editor's terminal:
```shell
npm run start:backend
```
This command spins up the backend server at the defined port. We can view the response from the server in JSON format by visiting the port URL on a browser— `http://localhost:8080/`. 

![Response from server](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7gnk3bniwmqngui6r191.png)

Now, we can make `GET` requests to the server URL on our frontend rather than making requests to the API endpoint directly. Let's head over to our previous front-end request to implement this change:
```js
const options = {
  method: "GET",
  url: "http://localhost:8080/",
};

Axios.request(options)
  .then((response) => {
    console.log(response.data);
  })
  .catch((error) => {
    console.log(error);
  });
```
Unlike our earlier client-side request that returns an error, the above request returns the data from the API, which we can view in the browser console or use in our application.


![Result from request](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdm6jt98cn5h77399fhz.png)

## Conclusion
CORS errors can be a real pain for front-end developers. However, understanding the underlying browser behavior helps us to properly visualize our approach to solving them. In this post, I briefly explained what CORS errors are, why they occur, and discussed possible ways of solving these errors. Finally, I implemented the recommended solution to fix CORS issues on a frontend application.