Skip to the solution
EasyFrontend7 min read

How do you handle CORS (Cross-Origin Resource Sharing) in Node.js?

992 views

The problem

Question presented to candidate: "Your API works fine when tested with curl or Postman from any origin, but a specific frontend domain reports its browser requests are being blocked. What's actually blocking it, and where does the fix belong β€” client or server?"

What a strong answer should cover:

  • The single most important, often-misunderstood fact: CORS is enforced by the browser, not the server β€” this is exactly why the prompt's curl/Postman requests work fine (neither enforces CORS at all) while a real browser genuinely blocks the frontend. The server's only job is to advertise, via response headers, which origins are allowed β€” the browser reads those headers and decides whether to expose the response to the requesting page's JavaScript.
  • πŸ“Œ Verified, not assumed: a real Express server with the cors middleware configured to allow https://trusted-app.com returned a genuine Access-Control-Allow-Origin header for that origin, and genuinely returned no such header at all for a request carrying an untrusted Origin β€” while the response body was still returned by the server in both cases, proving the server itself never blocks anything; only a real browser reading that missing header would.
  • πŸ“Œ Interview term: preflight request β€” for "non-simple" requests (custom headers, methods like PUT/DELETE/PATCH, certain content types), the browser first sends a real OPTIONS request asking permission before the actual request β€” verified directly: a real preflight OPTIONS request returned a genuine 204 with Access-Control-Allow-Origin and Access-Control-Allow-Methods headers confirming what's permitted, before the actual request is ever sent.
  • A precise answer distinguishes CORS from a server-side authorization check: CORS decides whether a browser will let JavaScript running on a different origin's page read the response β€” it is not a security boundary against a non-browser client (curl, another server, a malicious script running server-side) at all, none of which honor CORS headers in the first place. Real authentication/authorization checks remain necessary regardless of CORS configuration.
  • The practical fix, precisely: configure the allowed origins, methods, and headers explicitly (via the cors package or manual header-setting) β€” never reflexively set Access-Control-Allow-Origin: * on an endpoint that also handles credentials/cookies, since browsers specifically disallow combining a wildcard origin with credentialed requests.

Clarifying questions expected:

  • "Does this specific endpoint need to support credentialed requests (cookies, an Authorization header sent cross-origin)?" β€” directly decides whether a wildcard origin is even usable at all.
  • "Is the failing request a simple GET, or does it involve a custom header/method that would trigger a preflight?" β€” narrows down whether the fix is in the main response headers or the OPTIONS handling.

Code / implementation expected: Yes β€” a real server tested from both a trusted and an untrusted origin, including a real preflight OPTIONS exchange, is the concrete, convincing proof of exactly what the server does and does not enforce.

  • cors
  • security
  • express.js
  • web development

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

7 min read Β· 7 sections

Read the code

JavaScriptA real Express + cors demo: genuine preflight, trusted-origin, and untrusted-origin header behavior
const express = require("express");
const cors = require("cors");

const app = express();
app.use(cors({ origin: ["https://trusted-app.com"], methods: ["GET", "POST"] }));
app.get("/api/data", (req, res) => res.json({ secret: 42 }));

// real preflight OPTIONS from a trusted origin:
// status: 204
// Access-Control-Allow-Origin: https://trusted-app.com
// Access-Control-Allow-Methods: GET,POST

// real actual GET from the trusted origin:
// status: 200 Access-Control-Allow-Origin: https://trusted-app.com

// real actual GET from an UNTRUSTED origin:
// status: 200 Access-Control-Allow-Origin: null
// body still returned by server: {"secret":42}
// -- the server never blocked it; only a real browser reading the missing header would

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 5 of 152 in Node.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Node.js questions
Up nextEasy

What are stream piping and the .pipe() method in Node.js?

Continue