Getting the "CORS policy: No 'Access-Control-Allow-Origin' header" error when making API requests? This complete guide provides backend and frontend solutions for all frameworks including React, Node.js, Express, Spring Boot, and more.
Access to fetch at 'http://localhost:8080/api/data' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/api/data. (Reason: CORS header 'Access-Control-Allow-Origin' missing). Status code: 200.
TypeError: Failed to fetch
at fetch (native)
at async fetchData()
// Or with Axios:
AxiosError: Network Error
at XMLHttpRequest.handleError
The Problem: Your backend server is not sending CORS headers that allow your frontend to access it
Node.js/Express Solution:
npm install corsconst cors = require('cors');
app.use(cors());
Spring Boot Solution:
@CrossOrigin annotation:
@CrossOrigin(origins = "http://localhost:3000")
@RestController
public class ApiController { ... }
React Development Proxy (Quick Workaround):
package.json:
"proxy": "http://localhost:8080"
http://localhost:8080/api/data to /api/datanpm startCORS (Cross-Origin Resource Sharing) is a browser security feature that blocks requests from one origin (domain/port) to another.
Example of Cross-Origin Request:
CORS protects users from malicious websites making unauthorized requests to other websites using the user's credentials (cookies, session tokens).
Without CORS: An attacker's website could make requests to your bank's API using your logged-in session and steal your data.
With CORS: The browser blocks cross-origin requests unless the target server explicitly allows them with CORS headers.
// 1. Install cors package
// npm install cors
// 2. Import and use cors
const express = require('express');
const cors = require('cors');
const app = express();
// Enable CORS for all routes (development)
app.use(cors());
// Or enable CORS for specific origin (production)
app.use(cors({
origin: 'http://localhost:3000', // Your frontend URL
credentials: true, // If you need to send cookies
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
// Your routes
app.get('/api/data', (req, res) => {
res.json({ message: 'CORS is working!' });
});
app.listen(8080, () => {
console.log('Server running on port 8080');
});
// Add CORS headers manually (without cors package)
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000'); // Frontend URL
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', 'true');
// Handle preflight requests
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
// Your routes
app.get('/api/data', (req, res) => {
res.json({ message: 'CORS is working!' });
});
// Allow multiple specific origins
const allowedOrigins = [
'http://localhost:3000',
'http://localhost:3001',
'https://yourdomain.com',
'https://www.yourdomain.com'
];
app.use(cors({
origin: function (origin, callback) {
// Allow requests with no origin (like mobile apps or Postman)
if (!origin) return callback(null, true);
if (allowedOrigins.indexOf(origin) === -1) {
return callback(new Error('Not allowed by CORS'), false);
}
return callback(null, true);
},
credentials: true
}));
// On specific controller
@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/data")
public ResponseEntity getData() {
return ResponseEntity.ok("CORS is working!");
}
}
// Or on specific method
@RestController
@RequestMapping("/api")
public class ApiController {
@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/data")
public ResponseEntity getData() {
return ResponseEntity.ok("CORS is working!");
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // All endpoints
.allowedOrigins("http://localhost:3000") // Your frontend
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600); // Cache preflight response for 1 hour
}
};
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin("http://localhost:3000");
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
# 1. Install django-cors-headers
# pip install django-cors-headers
# 2. Add to INSTALLED_APPS in settings.py
INSTALLED_APPS = [
# ...
'corsheaders',
# ...
]
# 3. Add middleware (MUST be at the top)
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
# ... other middleware
]
# 4. Configure CORS settings
# For development - allow all origins
CORS_ALLOW_ALL_ORIGINS = True
# For production - specify allowed origins
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000",
"https://yourdomain.com",
]
# If you need credentials (cookies, auth)
CORS_ALLOW_CREDENTIALS = True
# Allowed methods
CORS_ALLOW_METHODS = [
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
]
# Allowed headers
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]
# 1. Install Flask-CORS
# pip install flask-cors
# 2. Import and use CORS
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# Enable CORS for all routes (development)
CORS(app)
# Or enable CORS for specific origin (production)
CORS(app, resources={
r"/api/*": {
"origins": ["http://localhost:3000"],
"methods": ["GET", "POST", "PUT", "DELETE"],
"allow_headers": ["Content-Type", "Authorization"],
"supports_credentials": True
}
})
@app.route('/api/data')
def get_data():
return {'message': 'CORS is working!'}
if __name__ == '__main__':
app.run(port=8080, debug=True)
// In Program.cs (ASP.NET Core 6+)
var builder = WebApplication.CreateBuilder(args);
// Add CORS policy
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowReactApp", policy =>
{
policy.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
builder.Services.AddControllers();
var app = builder.Build();
// Use CORS (must be before UseAuthorization)
app.UseCors("AllowReactApp");
app.UseAuthorization();
app.MapControllers();
app.Run();
// In your controller:
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
[HttpGet]
public IActionResult GetData()
{
return Ok(new { message = "CORS is working!" });
}
}
// In package.json, add:
{
"name": "my-app",
"version": "1.0.0",
"proxy": "http://localhost:8080"
// ... rest of package.json
}
// In your React component, change API calls:
// BEFORE (causes CORS error):
fetch('http://localhost:8080/api/data')
// AFTER (proxied - no CORS error):
fetch('/api/data')
// With Axios:
// BEFORE:
axios.get('http://localhost:8080/api/data')
// AFTER:
axios.get('/api/data')
npm start). The proxy only works in development, not production.
// Create src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': '/api', // Keep /api prefix
},
})
);
// Proxy multiple endpoints
app.use(
'/auth',
createProxyMiddleware({
target: 'http://localhost:8081',
changeOrigin: true,
})
);
};
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
secure: false,
// rewrite: (path) => path.replace(/^\/api/, '') // Remove /api prefix if needed
},
// Multiple proxies
'/auth': {
target: 'http://localhost:8081',
changeOrigin: true,
}
}
}
})
// Create proxy.conf.json in project root
{
"/api": {
"target": "http://localhost:8080",
"secure": false,
"changeOrigin": true
}
}
// In angular.json, modify serve options:
{
"projects": {
"your-app": {
"architect": {
"serve": {
"options": {
"proxyConfig": "proxy.conf.json"
}
}
}
}
}
}
# Or run with proxy flag: ng serve --proxy-config proxy.conf.json
Access-Control-Allow-Origin: * in production - it allows any website to access your APIhttps://yourdomain.comnpm start in development// Node.js/Express - Environment-based CORS
const corsOptions = {
origin: process.env.NODE_ENV === 'production'
? 'https://yourdomain.com'
: 'http://localhost:3000',
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
};
app.use(cors(corsOptions));
// React - Environment variables for API URL
// Create .env.development
REACT_APP_API_URL=http://localhost:8080
// Create .env.production
REACT_APP_API_URL=https://api.yourdomain.com
// In your code:
const API_URL = process.env.REACT_APP_API_URL;
fetch(`${API_URL}/api/data`)
.then(res => res.json())
.then(data => console.log(data));
Wrong Solution:
fetch('/api/data', { mode: 'no-cors' }) // DON'T DO THIS!
Why it's wrong: This makes the request but you can't read the response. You get an opaque response with no data.
Right Solution: Fix CORS on the backend instead.
Problem: Adding CORS headers in React/Vue/Angular code doesn't work.
Why: CORS headers must come from the SERVER (backend), not the client.
Solution: Configure CORS in your backend API server.
Problem: POST/PUT/DELETE requests fail even though GET works.
Why: Complex requests trigger a preflight OPTIONS request that must also return CORS headers.
Solution: Ensure your backend handles OPTIONS requests and returns proper headers (CORS middleware does this automatically).
Problem: Cookies/auth tokens aren't sent with requests.
Solution:
// Backend:
app.use(cors({
origin: 'http://localhost:3000',
credentials: true // Enable credentials
}));
// Frontend:
fetch('/api/data', {
credentials: 'include' // Include cookies
})
ESSENTIAL CORS HEADERS ====================== Access-Control-Allow-Origin: http://localhost:3000 - Specifies which origin can access the resource - Use specific origin in production, never use * with credentials Access-Control-Allow-Methods: GET, POST, PUT, DELETE - Specifies which HTTP methods are allowed Access-Control-Allow-Headers: Content-Type, Authorization - Specifies which headers can be sent in the request Access-Control-Allow-Credentials: true - Allows cookies and auth tokens to be sent - Cannot use with Access-Control-Allow-Origin: * Access-Control-Max-Age: 3600 - How long (in seconds) preflight response can be cached
Debugging checklist:
Visit our Interactive Diagnostic Wizard for personalized help.