Node.js CORS

CORS stands for Cross-Origin Resource Sharing. It is a browser safety rule that controls which websites may call your API. Many beginners meet CORS through a red error message in the browser console. This lesson explains the rule and shows how to configure it.

What Is an Origin

An origin is the combination of protocol, website name, and port.

 https://shop.com:443
 |        |        |
protocol  host     port

A change in any part creates a different origin. These addresses are all different origins.

  • https://shop.com and http://shop.com differ by protocol.
  • https://shop.com and https://api.shop.com differ by host.
  • http://localhost:3000 and http://localhost:5000 differ by port.

The Rule Behind CORS

Browsers use the same-origin policy. A page from one origin cannot read data from another origin unless the other server gives permission. Think of an apartment building. A visitor from outside needs the owner to put a name on the guest list.

 Page at http://localhost:3000
        |
        |  asks for data from http://localhost:5000/api
        v
 +-----------------+   Guest list says: allow 3000?
 |  API server     | ---------------------------------+
 |  port 5000      |                                  |
 +-----------------+                                  v
        Yes: browser delivers data     No: browser blocks it

The server still receives the request. The browser decides whether your page may read the answer.

The Typical Error

Access to fetch at 'http://localhost:5000/api'
from origin 'http://localhost:3000' has been blocked by CORS policy.

The fix lives on the server. Frontend code cannot repair it.

Enable CORS in Express

npm install cors
const express = require("express");
const cors = require("cors");

const app = express();
app.use(cors());

The default setting allows every origin. This option suits public APIs and local testing.

Allow One Origin

Real projects name the trusted sites.

app.use(cors({
  origin: "https://myshop.com"
}));

Allow a List of Origins

const allowed = ["https://myshop.com", "https://admin.myshop.com"];

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowed.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error("Origin not allowed"));
    }
  }
}));

More Settings

app.use(cors({
  origin: "https://myshop.com",
  methods: ["GET", "POST", "PUT", "DELETE"],
  allowedHeaders: ["Content-Type", "Authorization"],
  credentials: true,
  maxAge: 600
}));
  • methods lists permitted request types.
  • allowedHeaders lists permitted extra headers.
  • credentials allows cookies and login details to travel.
  • maxAge tells the browser to remember the answer for 600 seconds.

The setting credentials: true needs a specific origin. A wildcard star does not work with it.

Preflight Requests

Some requests need a permission check first. The browser sends a small OPTIONS request called a preflight. The server replies with the rules. The browser sends the real request after approval.

Browser                          Server
   |---- OPTIONS /api/items ------>|   May I send a DELETE?
   |<--- Allow: DELETE, GET --------|   Yes, you may.
   |---- DELETE /api/items/5 ----->|   Real request
   |<--- 200 OK -------------------|

The cors package handles preflight requests automatically.

Apply CORS to One Route

app.get("/public-data", cors(), (req, res) => {
  res.json({ open: true });
});

Set Headers by Hand

The package sets response headers for you. You can also write them yourself.

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "https://myshop.com");
  res.header("Access-Control-Allow-Methods", "GET,POST");
  next();
});

Safety Notes

  • CORS protects browser users. It does not replace login checks.
  • Tools such as curl and Postman ignore CORS entirely.
  • Avoid wildcard access on APIs that serve private data.
  • Keep the trusted origin list short and current.

Practice Tasks

  • Run an API on port 5000 and a page on port 3000, trigger the error, and fix it with the cors package.
  • Restrict the API to one origin and confirm another origin fails.
  • Limit allowed methods to GET and POST.