Aug 04, 2023
#CORS#Web Development#Cross-Origin Requests#Frontend
Table of Contents
Introduction
You've set up your server, tested it with a REST client like Postman, and everything is running smoothly. Confidently, you integrate it with your web application, expecting everything to work like magic. But then, out of nowhere, you're hit with a curveball - a dreaded CORS error.
So, what is CORS? Let's start with what the official MDN Web Docs says about CORS
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.
In simpler terms, CORS is a security mechanism built into browsers that requires specific HTTP headers to be exchanged between browsers and servers before allowing cross-origin requests.
The CORS Flow
Here's exactly what happens when a CORS request is made:
- Your browser sends an HTTP
OPTIONS
preflight request to the server
- The server responds with CORS headers
- The browser permits or deny the response
- If successful, the browser proceeds with the cross-origin request
- If not permitted, it's blocked due to a CORS policy error
Understanding CORS Headers
When a cross-origin request is made, browsers and servers exchange several important headers:
-
Access-Control-Allow-Origin
- Specifies which origins can access the resource
- Can be
*
(all origins) or specific domains
- MDN Documentation
-
Access-Control-Allow-Methods
- Lists allowed HTTP methods (GET, POST, PUT, etc.)
- Part of the preflight response
- MDN Documentation
-
Access-Control-Allow-Headers
-
Access-Control-Allow-Credentials
- Controls inclusion of credentials in requests
- Essential for cookie-based authentication
- MDN Documentation
CORS in Action
Let's see how CORS works with a simple Express server:
const express = require("express");
const app = express();
const port = 3000;
app.use(express.json());
app.get("/products", (req, res) => {
if (!products || products.length === 0) {
return res.status(404).json({ error: "Products not found" });
}
res.json(products);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
When we make a basic fetch request:
fetch(`http://localhost:3004/products`, {})
.then((response) => console.log(response.json()))
We encounter our first CORS error:
Working with Express
To handle CORS properly in Express, we can use the cors middleware:
const cors = require('cors');
app.use(cors());
This enables CORS with default settings, allowing requests from any origin:
Managing Origins
For better security, you can restrict allowed origins:
const allowedOrigins = ["http://localhost:3000", "https://example.com"]
app.use(cors({
origin: function (origin, callback) {
if(allowedOrigins.indexOf(origin) !== -1){
callback(null, origin)
} else {
callback(null, null);
}
}
}));
What's Next?
In Part 2, we'll dive deeper into:
- Different fetch modes and their behaviors
- Advanced CORS configurations
- Best practices for production environments
[Continue to Part 2: Understanding Fetch API Modes...]