How to handle CORS errors — with examples

Explore what is CORS and how to fix CORS errors using examples
Oct 31 2022 · 5 min read

What if anyone can access your bank account just with the UPI ID?

You will say that the UPI ID is shared with so many people, and if it can be compromised the fraud increases at a level we can’t even imagine! There must be a password kind of thing to make it person-proof.

Similarly, if CORS would not have been there then any clients(domains) can have access to your server!

But wait! Almost all modern browsers are honest enough and handle such a situation on our behalf. Especially if we’ve integrated js in our code, the browser will never allow us to access the cross-origin requests unless we allow it!

We are what we repeatedly do. Excellence, then, is not an act, but a habit. Try out Justly and start building your habits today!

Origin

It’s a combination of a URI scheme(HTTP/HTTPS), domain, and port.
for example, http://localhost:3000 or https://myblog.com

Same-Origin Policy

It’s the browser strategy, which stands for don’t look outside the circle! in simpler words.
i.e. If the web application is running on the domain https://myblog.com and it needs to access an API from https://api.myblog.com our browser won’t allow it to do so.

However, the domain is the same for both of them it will still consider them as different origins.

You will only be able to access the API if it’s also running at https://myblog.com, as it’s the same origin.

Nowadays, almost all browsers use a same-origin policy and hence prevent requests to/from different(cross) origins.

What is CORS

CORS is an HTTP-header based mechanism that allows resource sharing between clients and servers. By default it’s enabled, if you want to make it disabled, you can set an option mode:no-cors in request(not recommended).

There are cases when our web application brings out the data using APIs which are running on different(cross) domains. At that time, we need to assure our browser about we are the authorized users, making calls to the APIs.

Since it’s the responsibility of the browser to verify that only authentic clients have access to invoke the APIs.

Consider a case when your front end is running on http://localhost:3000 and the backend is on http://localhost:8080. Even if both hosts(domains) are the same, the ports are different, the browser will not allow any request from the frontend domain to the backend domain.

And there comes CORS in the picture.

CORS handling at server side

Consider the backend for a web application running on http://localhost:3000, according to the below code.

express server running at port 3000


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

app.get('/ping', (req, res) => {
  res.send('Pong!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
response of http://localhost:3000/ping
 


Consider the front end as a simple HTML page, as of below.

the front end of a web application

<html>
    <head>
        <title>Demo</title>
    </head>
    <body>
        <p>Welcome to CORS demo</p>
        <script type="text/javascript">

            async function invokeAPI() {
                var result = await fetch('http://localhost:3000/ping')         
                    .then(response => response.json());
                console.log(result)
            }
            window.onload = invokeAPI();    

        </script>
    </body>
</html>

When we run the above HTML code, as it has javascript and cross-origin API calls, we get an error like below.

We will explore majorly used response headers of CORS.

1. Access-Control-Allow-Origin

Error

Access-Control-Allow-Origin CORS error
 

Solution

Add cors middleware in the express server, as follows.

add CORS middleware

const cors = require('cors')
app.use(cors())

The cors middleware comes with origin: "*" , default. That’s for Access-Control-Allow-Origin CORS headers.

As you will see in dev tools, API response headers look like the below.

API response headers

Since * will allow all the origins to access our API at http://localhost:3000.
If you don’t wish to do so, override its value with a specific origin or the list of origins(if you have multiple clients). Like,

{
  "origin" : "http://localhost:8000"
    OR
  "origin" : ["http://localhost:8000", /\.example1\.com$/]
}

Note: It also allows setting regex as an origin.

The same can be achieved in any technology you’re working on. If the backend(server) is not accessible to you, then you might need to use a proxy server as an alternative.

2. Access-Control-Allow-Methods

By default, cors middleware allows all the HTTP request methods like GET,HEAD,PUT,PATCH,POST,DELETE , but according to the use case, you can always override its value as follows.

If you only want to allow GET APIs across the origin then, the code should be like below.

{
  "methods": "GET"
}

3. Access-Control-Allow-Headers

This CORS header is used to state which request headers will be accepted by the server.
Generally, it’s set to * unless you want to block specific request headers coming at the server.

4. Access-Control-Expose-Headers

This header is used to confirm which headers will be appended with headers.
In most cases, it’s majorly used when we want custom headers to be exchanged between client and server.

In our server origin, I have used just cors() means default CORS config. But now I want to append a custom header named token with the API response, hence modifying the route as follows.

app.get('/ping', (req, res) => {
  res.header("token", "test token")
  res.json('Pong!')
})

Problem
When I executed the frontend part(HTML) file, found that the custom header(token) is not shown in the list of response headers and only showing the default ones content-length and content-type.

In dev tools, you will see the custom headers included in the list of response headers of an API but it will not be available within the client.

the custom header hasn’t been exposed

Solution
By modifying default cors on the server side, we will get custom headers as below.

exposedHeaders: ['token'] /*your custom header key*/

The full code will look like this,

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

app.use(cors(
   {
    exposedHeaders: ['token'],
   }
))

app.get('/ping', (req, res) => {
  res.header("token", "test token")
  res.json('Pong!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

Let’s inspect whether the custom header is sent or not by the server. Modify invokeAPI function as follows,

async function invokeAPI() {
    await fetch('http://localhost:3000/ping')         
        .then(res => {
            for (var headers of res.headers.entries()) {
                console.log(headers[0]+ ': '+ headers[1]);
            }
      })
}
Exposed custom header output

Yee!! we got it. In this way, it’s also possible to set multiple custom headers with just an array of headers.

P.S. If you don’t see custom headers set as of the above image, try hard-refreshing the browser.

Finishing up

When working on the application, whose backend and frontend rely on different origins, we will be forced to configure CORS headers.

Appropriately setting CORS will save you from security vulnerabilities at an earlier stage. Also, enabling appropriate CORS allows us to set and get custom request/response headers.

Last but not least, the dangerous-looking CORS errors are actually dangerous for the unauthorized clients and savior for us!


nidhi-d image
Nidhi Davra
Web developer@canopas | Gravitated towards Web | Eager to assist


nidhi-d image
Nidhi Davra
Web developer@canopas | Gravitated towards Web | Eager to assist

background-image

Get started today

Let's build the next
big thing!

Let's improve your business's digital strategy and implement robust mobile apps to achieve your business objectives. Schedule Your Free Consultation Now.

Get Free Consultation
footer
Subscribe Here!
Follow us on
2024 Canopas Software LLP. All rights reserved.