Frontend and full-stack developers whose fetch() or axios requests fail with 'No Access-Control-Allow-Origin header is present'.
- ✓Basic experience calling REST APIs with fetch or axios
- ✓Express.js backend or Laravel API
🚀 What You Will Learn & Build
- ▸Why CORS is a browser security mechanism, NOT a server error
- ▸The role of preflight OPTIONS requests
- ▸Configuring Express cors middleware correctly for development and production
- ▸Configuring Laravel config/cors.php
1. What CORS Actually Is (And What It Isn't)
Tools like Postman and curl do NOT enforce CORS because they are not web browsers. If an API works in Postman but fails in React, it is a CORS configuration issue on your server.
2. The Proper Fix in Express.js
const express = require('express');
const cors = require('cors');
const app = express();
// Option A: Quick development allow-all (Never use in production)
// app.use(cors());
// Option B: Production whitelist (Recommended)
const allowedOrigins = [
'http://localhost:3000',
'https://yourdomain.com',
'https://www.yourdomain.com'
];
app.use(cors({
origin: function (origin, callback) {
// Allow requests with no origin (like mobile apps, curl, or Postman)
if (!origin || allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Blocked by CORS policy'));
}
},
credentials: true, // Allow cookies / authorization headers
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With']
}));
// Handle preflight requests
app.options('*', cors());3. The Proper Fix in Laravel
<?php
return [
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => [
'http://localhost:3000',
'https://yourdomain.com',
],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];✨ Expected Output & Verification
Inspect the response headers in Chrome DevTools Network Tab: Access-Control-Allow-Origin: http://localhost:3000 Access-Control-Allow-Credentials: true HTTP 200 OK without console red error flags.
🧪 How to Test the Implementation
- 1Trigger fetch request from React frontend and inspect browser console
- 2Check Network tab for the preflight OPTIONS request returning 204 or 200
⚠️ Common Errors & How to Fix Them
Root Cause: Setting origin: '*' while simultaneously setting credentials: true.
Fix: Specify exact origins (e.g. 'http://localhost:3000') instead of '*' when sending cookies or Bearer tokens.
🛡️ Security Considerations & Best Practices
- !Never leave Access-Control-Allow-Origin: * on production endpoints handling sensitive authenticated user data.
❓ Frequently Asked Questions (FAQ)
No. CORS headers must be sent by the server responding to the request. In development, you can use a Vite/Next.js proxy, but production requires backend headers.
📌 Summary of Key Takeaways
- ✓CORS is enforced by browsers to prevent malicious scripts from reading third-party data.
- ✓Fix it on the server by sending Access-Control-Allow-Origin headers.
Official References & Further Reading
- 🔗MDN Web Docs: Cross-Origin Resource Sharing (CORS)— Authoritative explanation of preflight requests and CORS headers.
Written by Manoj Neupane
AuthorSoftware developer and programming instructor, Nepal
Building software systems and SaaS platforms with Laravel, Next.js, and Node.js. Passionate about helping students and developers in Nepal master practical, real-world development skills.