What is CORS in React?
Cross-Origin Resource Sharing (CORS) is a browser security mechanism that controls whether a React frontend application can access resources from a different domain (origin).
Understanding “Origins”
An origin consists of three parts:
- Protocol:
http://orhttps:// - Domain:
example.comorapi.example.com - Port:
:3000,:5000, etc.
Examples of cross-origin requests:
- Your React app runs on
http://localhost:3000 - Your API runs on
http://localhost:5000← Different origin = CORS needed - Your frontend is
https://myapp.com - Your API is
https://api.myapp.com← Different subdomain = CORS needed
Why CORS Matters for React Developers
When you install React in VS Code and build an app that fetches data from an external API, CORS becomes critical. Without proper CORS configuration, you’ll see errors like:
Access to XMLHttpRequest at 'http://api.example.com/data'
from origin 'http://localhost:3000' has been blocked by CORS policy
Key point: CORS is enforced by browsers—it’s a client-side security feature, but you fix it on the server side.
Why CORS Errors Occur
The Browser’s CORS Check
When your React app makes a request to a different origin, the browser automatically:
- Sends a preflight request (OPTIONS) to check if the cross-origin request is allowed
- Inspects server response headers for
Access-Control-Allow-Origin - Blocks the request if the header isn’t present or doesn’t match the origin
Common CORS Error Scenarios
| Scenario | Error Message | Solution |
|---|---|---|
| React on localhost:3000, API on localhost:5000 | “has been blocked by CORS policy” | Enable CORS on backend API |
| Wrong origin in whitelist | “Origin not allowed” | Add your frontend domain to CORS allowlist |
| Missing credentials header | “Credentials mode is ‘include'” | Set credentials: 'include' + proper headers |
| Preflight timeout | “Failed to load OPTIONS” | Increase timeout; check server is running |
How to Enable CORS in React (3 Methods)
Method 1: Backend CORS Middleware (Recommended) ✅
This is the production-safe approach. Configure CORS on your Node.js/Express backend.
Pros:
- Works in production
- Secure—whitelist specific origins
- Standard approach
- No code changes needed in React
Cons:
- Requires backend access
- Requires restart after changes
Step 1: Install CORS Package
bash
npm install cors
Step 2: Add CORS Middleware to Express Server
javascript
const express = require('express');
const cors = require('cors');
const app = express();
// Option A: Allow requests from specific origin (SECURE)
const corsOptions = {
origin: 'http://localhost:3000', // Your React app origin
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
credentials: true, // Allow cookies/auth headers
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
// OR Option B: Allow all origins (DEVELOPMENT ONLY)
app.use(cors());
// Your routes
app.get('/api/data', (req, res) => {
res.json({ message: 'CORS enabled!' });
});
app.listen(5000, () => {
console.log('API running on http://localhost:5000');
});
Step 3: Fetch from React App
javascript
// In your React component
useEffect(() => {
fetch('http://localhost:5000/api/data', {
method: 'GET',
credentials: 'include' // If using cookies
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error('CORS Error:', err));
}, []);
Method 2: Configure CORS for Specific Routes
Enable CORS only on routes that need it (more secure):
javascript
const express = require('express');
const cors = require('cors');
const app = express();
const corsOptions = {
origin: ['http://localhost:3000', 'https://myapp.com'],
methods: ['GET', 'POST'],
credentials: true
};
// Apply CORS only to specific route
app.get('/api/public-data', cors(corsOptions), (req, res) => {
res.json({ data: 'Public data with CORS' });
});
// This route has NO CORS
app.get('/api/admin', (req, res) => {
res.status(403).json({ error: 'Forbidden' });
});
app.listen(5000);
Best for: Different CORS rules for different endpoints.
Method 3: Manual CORS Headers (Advanced)
If you can’t use the CORS package, set headers manually:
javascript
const express = require('express');
const app = express();
app.use((req, res, next) => {
// Allow specific origin
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
// Allow credentials
res.setHeader('Access-Control-Allow-Credentials', 'true');
// Allowed HTTP methods
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
// Allowed headers
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// Max age for preflight cache (seconds)
res.setHeader('Access-Control-Max-Age', '86400');
// Handle preflight requests
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
app.get('/api/data', (req, res) => {
res.json({ message: 'Works without cors package!' });
});
app.listen(5000);
Enable CORS in Express.js Backend
Complete Express + CORS Setup (Step-by-Step)
If you’re using React with a PHP backend or any other backend, here’s the standard Express approach:
1. Create a new Express server:
bash
mkdir my-api
cd my-api
npm init -y
npm install express cors
2. Create server.js:
javascript
const express = require('express');
const cors = require('cors');
const app = express();
// Middleware
app.use(express.json());
// CORS Configuration
const corsOptions = {
origin: [
'http://localhost:3000',
'http://localhost:5173', // Vite default
'https://yourdomain.com'
],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
credentials: true,
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
// Routes
app.get('/api/users', (req, res) => {
res.json({
users: [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' }
]
});
});
app.post('/api/users', (req, res) => {
const newUser = req.body;
res.status(201).json({ id: 3, ...newUser });
});
// Error handling
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Server error' });
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`API server running on http://localhost:${PORT}`);
});
3. Start the server:
bash
node server.js
4. From your React app, fetch data:
javascript
import { useEffect, useState } from 'react';
function App() {
const [users, setUsers] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
// Make API call
fetch('http://localhost:5000/api/users', {
method: 'GET',
credentials: 'include'
})
.then(res => res.json())
.then(data => setUsers(data.users))
.catch(err => setError(err.message));
}, []);
return (
<div>
{error ? <p>Error: {error}</p> : users.map(u => <p>{u.name}</p>)}
</div>
);
}
export default App;
CORS Configuration Best Practices
1. Never Use origin: '*' in Production ⚠️
javascript
// ❌ INSECURE
app.use(cors()); // Allows ALL origins
// ✅ SECURE
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
credentials: true
}));
2. Use Environment Variables
javascript
const corsOptions = {
origin: process.env.NODE_ENV === 'production'
? 'https://yourdomain.com'
: 'http://localhost:3000',
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE']
};
app.use(cors(corsOptions));
3. Whitelist Multiple Domains Safely
javascript
const allowedOrigins = [
'http://localhost:3000',
'https://yourdomain.com',
'https://www.yourdomain.com',
'https://staging.yourdomain.com'
];
const corsOptions = {
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true
};
app.use(cors(corsOptions));
4. Handle Preflight Requests Explicitly
javascript
// Preflight responses should be FAST
app.options('/api/*', cors());
// Or specific endpoints
app.options('/api/data', cors());
app.get('/api/data', (req, res) => {
res.json({ data: 'value' });
});
5. Know Your HTTP Methods for React Best Practices
- GET: Fetch data (safe)
- POST: Create data (requires CORS preflight if not simple request)
- PUT/PATCH: Update data (requires CORS preflight)
- DELETE: Remove data (requires CORS preflight)
Troubleshooting CORS Errors
Error: “Access to XMLHttpRequest blocked by CORS policy”
Cause: Server isn’t sending Access-Control-Allow-Origin header
Fix:
javascript
app.use(cors({
origin: 'http://localhost:3000'
}));
Error: “Credentials mode is ‘include’ but Access-Control-Allow-Credentials is missing”
Cause: You sent credentials: 'include' in fetch but server doesn’t allow it
Fix:
javascript
const corsOptions = {
origin: 'http://localhost:3000',
credentials: true // ← Add this
};
app.use(cors(corsOptions));
And in React:
javascript
fetch('http://localhost:5000/api/data', {
credentials: 'include' // ← Add this
})
Error: “preflight request to (OPTIONS) failed”
Cause: Server doesn’t handle OPTIONS requests
Fix:
javascript
app.options('*', cors());
// OR specific route
app.options('/api/data', cors());
Error: “Origin ‘http://localhost:3000‘ is not allowed”
Cause: Your origin isn’t in the CORS whitelist
Fix: Check your corsOptions.origin value matches exactly (protocol + domain + port):
javascript
// If running on http://localhost:3000, ensure:
origin: 'http://localhost:3000' // NOT https, NOT localhost:5000
Using a Proxy During Development
If you can’t access the backend directly, use a proxy:
In package.json of your React app:
json
{
"proxy": "http://localhost:5000"
}
Then fetch without the full URL:
javascript
fetch('/api/data') // Proxies to http://localhost:5000/api/data
⚠️ Note: This only works in development with create-react-app. For Vite React projects, configure in vite.config.js:
javascript
export default {
server: {
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
}
Security Considerations
CORS Doesn’t Prevent All Attacks
CORS protects against cross-site request forgery (CSRF) but doesn’t prevent:
- Direct API access via tools like Postman
- Bot attacks
- DDoS attacks
Always validate on the server side.
Secure CORS Headers
javascript
const corsOptions = {
origin: process.env.ALLOWED_ORIGINS?.split(','),
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true,
maxAge: 3600, // Preflight cache time
allowedHeaders: ['Content-Type', 'Authorization']
};
app.use(cors(corsOptions));
// Add security headers
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
next();
});
Check Authorization Headers
Even with CORS enabled, verify authentication:
javascript
app.get('/api/protected', cors(corsOptions), (req, res) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token || !verifyToken(token)) {
return res.status(401).json({ error: 'Unauthorized' });
}
res.json({ data: 'Sensitive data' });
});
FAQs
Q: Do I need to enable CORS in React itself?
A: No. CORS is a server-side configuration only. React can’t bypass browser CORS restrictions. Always configure your backend API server.
Q: Can I enable CORS for specific HTTP methods?
A: Yes. In the methods option:
javascript
app.use(cors({
origin: 'http://localhost:3000',
methods: ['GET', 'POST'] // DELETE and PUT blocked
}));
Q: Is it safe to use origin: '*'?
A: Only for public APIs with no sensitive data. Never use in production for authenticated endpoints. It allows any website to make requests.
Q: Why does my preflight request timeout?
A: Common causes:
- Backend server not running
- Firewall blocking the port
- Server not handling OPTIONS requests
- Network issues
Debug with browser DevTools Network tab → check OPTIONS request status.
Q: How do I enable CORS for file uploads?
A: CORS works the same for file uploads:
javascript
app.post('/api/upload', cors(corsOptions), (req, res) => {
// Handle file upload
});
Q: Should I use CORS or a proxy?
A:
- Development: Use proxy for convenience
- Production: Use CORS on backend for proper security
- Both: Use both—proxy in dev, CORS in prod
Q: How does CORS interact with authentication?
A: Add credentials: true in both server and client:
// Server
app.use(cors({
origin: 'http://localhost:3000',
credentials: true
}));
// React
fetch('http://localhost:5000/api/data', {
credentials: 'include'
})
Related Resources & Next Steps
Ready to build with CORS enabled? Check out these related guides:
- How to Install React JS in Visual Studio Code — Start here if you’re setting up a new project
- What is npm in React? — Understand package management for installing CORS
- How to Create Routes in React JS — Build multi-page apps with backend API calls
- How to Upload Files in React JS — Handle file uploads with CORS
- React Best Practices to Up Your Game in 2023 — Write secure, maintainable code
- React Developer Tools in Chrome — Debug API calls and component state
- Troubleshooting “sh: react-scripts: command not found“ — Fix common React setup errors
Conclusion
Enabling CORS in React JS is essential for modern web applications. Remember:
✅ CORS is configured on the backend, not in React
✅ Use specific origins in production, never origin: '*'
✅ Always validate requests server-side, CORS isn’t enough for security
✅ Whitelist trusted domains to prevent unauthorized access
✅ Use credentials: true carefully with authentication
By following these practices, you’ll build secure, scalable React applications that communicate seamlessly with backend APIs.