DEV Community

Dera Okeke
Dera Okeke

Posted on • Updated on

Eliminate CORS Policy Errors on a Frontend Application

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

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 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 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:

npm init
Enter fullscreen mode Exit fullscreen mode

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: This is a minimalistic back-end web application framework for Node.js.
  • cors: A Node.js package that enables CORS in an Express middleware.
  • 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:

npm i express cors axios
Enter fullscreen mode Exit fullscreen mode

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.

  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);
    });
Enter fullscreen mode Exit fullscreen mode

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

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:

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}`);
});
Enter fullscreen mode Exit fullscreen mode

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.
require("dotenv").config();
Enter fullscreen mode Exit fullscreen mode
  • 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 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:

"start:backend": "node index.js",
Enter fullscreen mode Exit fullscreen mode

This defines the start script for running the server locally. Depending on your original setup, your package.json file should look something like this:

{  
  "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"
  }
}   
Enter fullscreen mode Exit fullscreen mode

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:

npm run start:backend
Enter fullscreen mode Exit fullscreen mode

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

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:

const options = {
  method: "GET",
  url: "http://localhost:8080/",
};

Axios.request(options)
  .then((response) => {
    console.log(response.data);
  })
  .catch((error) => {
    console.log(error);
  });
Enter fullscreen mode Exit fullscreen mode

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

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.

Latest comments (1)

Collapse
 
fruntend profile image
fruntend

Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍