🌐 Adding CORS Headers to Avoid CORS Issues (with Node.js http Module)

Introduction

When a web application running on one origin (domain, protocol, or port) attempts to access resources from another origin, browsers enforce the Same-Origin Policy. To safely allow cross-origin requests, servers must include appropriate CORS (Cross-Origin Resource Sharing) headers in their responses.

Information

CORS is a browser security feature. Server-to-server requests are generally not restricted by CORS.

What is CORS?

CORS is a mechanism that allows a server to specify which origins, HTTP methods, and request headers are permitted to access its resources. Without the correct CORS headers, browsers block cross-origin requests even if the server responds successfully.

🌍 Browser Sends Request
📡 Request Reaches Server
📝 Server Sends CORS Headers
Browser Checks Headers
✅ Allowed → Response Available to JavaScript
❌ Not Allowed → Browser Blocks Access

Understanding Origins

An origin is defined by the combination of protocol, hostname, and port. Two URLs belong to the same origin only if all three match.

Current OriginRequested OriginSame Origin?
http://localhost:3000http://localhost:3000✅ Yes
http://localhost:3000http://localhost:5000❌ Different Port
http://localhost:3000https://localhost:3000❌ Different Protocol
http://localhost:3000http://example.com❌ Different Host

Common CORS Headers

HeaderPurpose
Access-Control-Allow-OriginSpecifies which origin can access the resource.
Access-Control-Allow-MethodsLists the allowed HTTP methods.
Access-Control-Allow-HeadersLists the allowed request headers.
Access-Control-Allow-CredentialsAllows cookies and authentication credentials.
Access-Control-Max-AgeSpecifies how long preflight responses may be cached.

Adding Basic CORS Headers

The simplest configuration allows requests from any origin by setting the Access-Control-Allow-Origin header to *.

Allow requests from any origin

const http = require("http");

const server = http.createServer((req, res) => {

  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Content-Type", "application/json");

  res.end(JSON.stringify({
    message: "CORS enabled"
  }));

});

server.listen(3000);

Warning

Using * allows every origin to access your API. While convenient for development or public APIs, production applications often restrict access to specific trusted origins.

Allowing Specific Origins

Instead of allowing all origins, you can permit only a trusted website.

Allow a specific origin

res.setHeader(
  "Access-Control-Allow-Origin",
  "http://localhost:5173"
);

Allowing Multiple HTTP Methods

Browsers need to know which request methods are permitted.

Allow HTTP methods

res.setHeader(
  "Access-Control-Allow-Methods",
  "GET, POST, PUT, DELETE, OPTIONS"
);

Allowing Request Headers

If clients send custom request headers such as Authorization or Content-Type, the server should explicitly allow them.

Allow request headers

res.setHeader(
  "Access-Control-Allow-Headers",
  "Content-Type, Authorization"
);

Handling Preflight Requests

Before sending certain cross-origin requests, browsers send an OPTIONS request called a preflight request. The server must respond successfully before the browser sends the actual request.

🌍 Browser Wants to Send POST Request
📨 Send OPTIONS Request
📝 Server Returns Allowed Methods and Headers
✅ Browser Approves the Request
📤 Actual POST Request Is Sent

Handle OPTIONS requests

if (req.method === "OPTIONS") {

  res.writeHead(204, {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
    "Access-Control-Allow-Headers": "Content-Type, Authorization"
  });

  return res.end();
}

Complete Example

HTTP server with CORS support

const http = require("http");

const server = http.createServer((req, res) => {

  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader(
    "Access-Control-Allow-Methods",
    "GET, POST, PUT, DELETE, OPTIONS"
  );
  res.setHeader(
    "Access-Control-Allow-Headers",
    "Content-Type, Authorization"
  );

  if (req.method === "OPTIONS") {
    res.writeHead(204);
    return res.end();
  }

  res.writeHead(200, {
    "Content-Type": "application/json"
  });

  res.end(JSON.stringify({
    message: "Hello from the API"
  }));

});

server.listen(3000, () => {
  console.log("Server running on port 3000");
});

Request Lifecycle

Client Sends Request
Server Adds CORS Headers
Request Method
Browser Validates CORS
Response Delivered
OPTIONS → Return 204
GET/POST/PUT/DELETE → Process Request

Testing CORS

  1. Start the Node.js server.
  2. Create or open a frontend application running on a different origin.
  3. Send an HTTP request using fetch() or another HTTP client.
  4. Open the browser's Developer Tools and inspect the Network tab.
  5. Verify that the CORS headers appear in the response.

Example Frontend Request

Using fetch()

fetch("http://localhost:3000")
  .then(response => response.json())
  .then(data => {
    console.log(data);
  });

Common CORS Errors

ErrorCauseSolution
CORS policy blocked requestMissing or incorrect CORS headersAdd appropriate Access-Control-Allow-* headers.
Preflight request failedOPTIONS request not handledReturn a successful response for preflight requests.
Header not allowedMissing allowed request headersUpdate Access-Control-Allow-Headers.
Method not allowedMissing allowed methodsUpdate Access-Control-Allow-Methods.

Best Practices

  • Allow only trusted origins in production.
  • Support preflight OPTIONS requests when necessary.
  • Return only the methods and headers your API actually supports.
  • Use Access-Control-Allow-Credentials only when required.
  • Regularly review your CORS policy as your application evolves.

Best Practice

Avoid combining Access-Control-Allow-Origin: * with credentialed requests. When credentials (such as cookies or authentication headers) are required, specify the exact allowed origin instead of using the wildcard.

Official Documentation

MDN Web Docs: Cross-Origin Resource Sharing (CORS) and Node.js HTTP Module Documentation

Summary

Summary

CORS enables browsers to safely access resources across different origins. By adding headers such as Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers, and by correctly handling preflight OPTIONS requests, you can build Node.js HTTP servers that communicate reliably with frontend applications while maintaining appropriate security.