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
corspackage - 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
corspackage.
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
npm install cors
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);
curl -i http://localhost:4208/no-cors | grep -i access-control
(no Access-Control headers)
curl -i -H "Origin: https://example.com" http://localhost:4208/with-cors | grep -i access-control
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
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
- Install
cors, registerapp.use(cors())on an app, and confirm withcurl -ithatAccess-Control-Allow-Origin: *appears on a route registered after it. - Register a route before
app.use(cors()), confirm it lacks the CORS header, then move it after and confirm the header now appears. - 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. - 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.