CodingNic

Middleware

CORS: Controlling Cross-Origin Requests

Middleware 10 min read

CORS: Controlling Cross-Origin Requests

Objectives

By the end of this lesson, you should be able to:

  • Explain what CORS is and why browsers enforce it
  • Enable CORS on an Express app with the cors package
  • Recognize where middleware order affects which routes get CORS headers

💡 Why this matters: A browser blocks a frontend running on one domain from calling an API on a different domain, unless that API explicitly allows it. Any API meant to be called from a separate frontend (the exact setup Module 6 of the frontend track’s Fetch API lesson assumed) needs CORS configured correctly, or every request from the browser fails.

⚠️ A note on verification: every snippet and every response shown below was actually run and tested with real HTTP requests, using the cors package.

What CORS Is

CORS (Cross-Origin Resource Sharing) is a browser security mechanism, not something Node.js or Express does on its own. By default, a browser blocks JavaScript running on https://myapp.com from successfully reading a response from https://api.example.com, a different origin (different domain, port, or protocol), unless that API’s response explicitly says it’s allowed, via an Access-Control-Allow-Origin header. This isn’t optional or a bug to work around, it’s a deliberate browser protection against a malicious site silently reading data from another site a user is logged into.

Enabling CORS

bash
npm install cors
javascript
const express = require('express');
const cors = require('cors');
const app = express();

app.get('/no-cors', (req, res) => {
  res.json({ message: 'no CORS headers' });
});

app.use(cors());

app.get('/with-cors', (req, res) => {
  res.json({ message: 'CORS enabled' });
});

app.listen(4208);
bash
curl -i http://localhost:4208/no-cors | grep -i access-control
text
(no Access-Control headers)
bash
curl -i -H "Origin: https://example.com" http://localhost:4208/with-cors | grep -i access-control
text
Access-Control-Allow-Origin: *

cors() (with no arguments) adds Access-Control-Allow-Origin: *, allowing any origin to call routes registered after it. Notice /no-cors, registered before app.use(cors()), has no CORS headers at all, this is Lesson 1’s registration-order rule in action, /no-cors matches and completes before ever reaching the cors() middleware registered below it.

Restricting to Specific Origins

javascript
app.use(cors({
  origin: 'https://myapp.com'
}));

Passing an options object restricts Access-Control-Allow-Origin to a specific origin instead of *, appropriate for a real API meant to be called only from a known frontend, rather than from any website on the internet.

Try It

  1. Install cors, register app.use(cors()) on an app, and confirm with curl -i that Access-Control-Allow-Origin: * appears on a route registered after it.
  2. Register a route before app.use(cors()), confirm it lacks the CORS header, then move it after and confirm the header now appears.
  3. Restrict CORS to a specific origin using the options object, and explain, in your own words, when origin: '*' would be inappropriate for a real application.
  4. Explain, in your own words, why CORS is enforced by the browser, not by the server, even though the server sends the header that controls it.

Recap

  • CORS is a browser security mechanism blocking cross-origin requests unless the server explicitly allows them via Access-Control-Allow-Origin.
  • cors() middleware adds this header automatically, cors({ origin: '...' }) restricts it to a specific origin.
  • Middleware registration order (Lesson 1) still applies, a route registered before app.use(cors()) won’t get CORS headers.

Next lesson: cookie-parser, reading cookies sent with a request.