Fix CORS Policy: No 'Access-Control-Allow-Origin' Header Present
Quick Answer
- Conclusion: The
corsnpm package is the standard solution for enabling cross-origin requests in Express.js and other Node.js frameworks. Install it withnpm install corsand addapp.use(cors())before your routes. - First checks: Verify the middleware is registered before all route handlers, the server has been restarted after installation, and the frontend URL matches the configured origin (including port numbers).
- Minimal fix: Run
npm install cors, then addconst cors = require('cors'); app.use(cors());to your server entry file and restart the server. - Version boundary: Works with Express.js 4.x and 5.x, Koa, Fastify, and other Node.js frameworks. Compatible with all modern browsers (Chrome, Firefox, Safari, Edge).
What Problem It Solves
The cors package solves the browser's same-origin policy restriction that blocks web pages from making requests to a different domain, protocol, or port. When a frontend application (e.g., React on http://localhost:3000) tries to fetch data from a backend API on a different origin (e.g., http://localhost:4000), the browser blocks the request unless the server explicitly allows it via CORS headers.
Installation and Quick Start
Install the package:
BASHnpm install cors
Basic usage with Express.js:
JAVASCRIPTconst express = require('express'); const cors = require('cors'); const app = express(); // Enable all CORS requests (development only) app.use(cors()); app.get('/api/data', (req, res) => { res.json({ message: 'CORS-enabled response' }); }); app.listen(3000);
Minimal Working Configuration
For a single-origin frontend application:
JAVASCRIPTconst cors = require('cors'); app.use(cors({ origin: 'http://localhost:3000' }));
For multiple allowed origins:
JAVASCRIPTapp.use(cors({ origin: ['http://localhost:3000', 'http://localhost:8080'] }));
Root Cause Analysis
The CORS error occurs because browsers enforce a same-origin policy that blocks cross-origin HTTP requests initiated by scripts. When the browser sends a cross-origin request, it first checks the server's response for the Access-Control-Allow-Origin header. If this header is missing or doesn't match the requesting origin, the browser blocks the response and throws the error.
The cors middleware automatically adds the required CORS headers to your server's responses, including:
Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-HeadersAccess-Control-Allow-Credentials
Common Errors and Fixes
| Error | Solution |
|---|---|
No 'Access-Control-Allow-Origin' header is present | Install cors and register middleware before routes: npm install cors then app.use(cors()) |
Request header field content-type is not allowed | Explicitly allow headers: cors({ allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'] }) |
Access-Control-Allow-Credentials header must be 'true' | Enable credentials: cors({ origin: 'http://localhost:3000', credentials: true }) |
Request client is not a secure context | Serve frontend over HTTPS or localhost, or configure private network access headers |
Production Notes and Security Checks
Critical security limitations of default configuration:
cors()without options allows all origins (*), which is a security risk in production- Does not support credential passing (cookies, HTTP auth) without explicit
credentials: true - No preflight request caching by default, which can degrade performance
- Custom response headers are not exposed to the browser without
exposedHeaders
Production-safe configuration:
JAVASCRIPTconst corsOptions = { origin: process.env.ALLOWED_ORIGINS ? process.env.ALLOWED_ORIGINS.split(',') : ['http://localhost:3000'], methods: ['GET', 'POST', 'PUT', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'], exposedHeaders: ['X-Total-Count'], credentials: true, maxAge: 86400 // Cache preflight for 24 hours }; app.use(cors(corsOptions));
Security checklist:
- Always configure an origin whitelist using environment variables
- Never use wildcard (
*) in production - Restrict allowed HTTP methods to only what your API needs
- Limit allowed request headers
- Enable preflight caching with
maxAgeto reduce OPTIONS requests - When using credentials, you must specify an explicit origin (not
*) - Regularly review and update your origin whitelist
FAQ
Q: Why do I still get CORS errors after configuring cors()?
A: Common causes include: 1) The middleware is registered after route handlers instead of before them; 2) The server hasn't been restarted; 3) The frontend URL doesn't match the configured origin (check port numbers); 4) Custom request headers are used but not declared in allowedHeaders; 5) The request includes credentials (cookies) but credentials: true is not set.
Q: How do I restrict access to only specific domains?
A: Use the origin option with a string or array: cors({ origin: 'https://app1.com' }) for a single domain, or cors({ origin: ['https://app1.com', 'https://app2.com'] }) for multiple domains. You can also use a function for dynamic validation: cors({ origin: function(origin, callback) { /* custom logic */ } }).
Q: What are the best practices for CORS in production?
A: 1) Store allowed origins in environment variables; 2) Avoid wildcard origins; 3) Limit HTTP methods to what your API actually uses; 4) Restrict allowed headers; 5) Enable preflight caching with maxAge; 6) For credentials, specify explicit origins; 7) Regularly audit your CORS configuration; 8) Consider using a reverse proxy (like Nginx) to handle CORS headers instead of the application layer for better performance.