search
Javascript star Featured

How to Fix Access to Fetch Blocked by CORS Policy Error

Learn how to fix the Access to fetch blocked by CORS policy error. Complete guide with solutions for cross-origin requests, headers, and server configuration.

person By Gautam Sharma
calendar_today January 8, 2026
schedule 11 min read
JavaScript CORS Fetch Error Handling API HTTP

The ‘Access to fetch blocked by CORS policy’ error is one of the most common issues developers encounter when making cross-origin HTTP requests. This error occurs when a web application tries to make a request to a different domain, protocol, or port than the one the application was served from, and the server doesn’t explicitly allow such requests.

This comprehensive guide provides complete solutions to resolve the CORS fetch error with practical examples and configuration techniques.


Understanding the CORS Fetch Error

Cross-Origin Resource Sharing (CORS) is a security feature implemented by web browsers to prevent malicious websites from making unauthorized requests to other domains. When you see this error, it means the browser is blocking your fetch request because it violates the same-origin policy.

Common Error Messages:

  • Access to fetch at 'URL' from origin 'ORIGIN' has been blocked by CORS policy
  • No 'Access-Control-Allow-Origin' header is present on the requested resource
  • CORS policy: Response to preflight request doesn't pass access control check
  • Fetch API cannot load URL: No 'Access-Control-Allow-Origin' header

Common Causes and Solutions

1. Missing Access-Control-Allow-Origin Header

The most common cause is a server not sending the required CORS headers.

❌ Problem Scenario:

// ❌ This will fail with CORS error
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('CORS Error:', error));

✅ Solution: Server-Side Configuration

// ✅ Server configuration (Node.js/Express example)
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*'); // Allow all origins (not recommended for production)
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
  
  if (req.method === 'OPTIONS') {
    res.sendStatus(200);
  } else {
    next();
  }
});

2. Production-Safe CORS Configuration

For production applications, use specific origins instead of wildcard.

❌ Problem Scenario:

// ❌ Wildcard allows all origins (security risk)
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*'); // ❌ Security risk in production
  next();
});

✅ Solution: Specific Origins

// ✅ Production-safe CORS configuration
const allowedOrigins = [
  'https://yourdomain.com',
  'https://www.yourdomain.com',
  'http://localhost:3000', // For development
  'http://localhost:3001'
];

app.use((req, res, next) => {
  const origin = req.headers.origin;
  if (allowedOrigins.includes(origin)) {
    res.header('Access-Control-Allow-Origin', origin);
  }
  
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Auth-Token');
  res.header('Access-Control-Allow-Credentials', 'true');
  
  if (req.method === 'OPTIONS') {
    res.sendStatus(200);
  } else {
    next();
  }
});

Solution 1: Backend Server Configuration

Configure your backend server to handle CORS properly.

Express.js with CORS Middleware:

// server.js
const express = require('express');
const cors = require('cors');
const app = express();

// ✅ Simple CORS configuration
app.use(cors());

// ✅ Advanced CORS configuration
const corsOptions = {
  origin: [
    'https://yourdomain.com',
    'https://www.yourdomain.com',
    'http://localhost:3000'
  ],
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  allowedHeaders: [
    'Origin', 
    'X-Requested-With', 
    'Content-Type', 
    'Accept', 
    'Authorization',
    'X-Auth-Token'
  ],
  credentials: true,
  optionsSuccessStatus: 200
};

app.use(cors(corsOptions));

// Your routes
app.get('/api/data', (req, res) => {
  res.json({ message: 'Data from server' });
});

app.listen(3001, () => {
  console.log('Server running on port 3001');
});

Fastify with CORS:

// fastify-server.js
const fastify = require('fastify')({ logger: true });
const cors = require('@fastify/cors');

// Register CORS plugin
fastify.register(cors, {
  origin: [
    'https://yourdomain.com',
    'https://www.yourdomain.com',
    'http://localhost:3000'
  ],
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true
});

fastify.get('/api/data', async (request, reply) => {
  return { message: 'Data from Fastify server' };
});

fastify.listen({ port: 3001 }, (err) => {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
});

Solution 2: Frontend Workarounds

Implement frontend solutions when you can’t control the server.

Using a Proxy Server:

// ✅ Use a proxy to avoid CORS
const PROXY_URL = 'https://cors-anywhere.herokuapp.com/'; // Example proxy
const API_URL = 'https://api.example.com/data';

fetch(`${PROXY_URL}${API_URL}`)
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Proxy error:', error));

Using a Custom Proxy Endpoint:

// ✅ Create your own proxy endpoint
// In your backend (Node.js example)
app.get('/proxy/:url(*)', async (req, res) => {
  try {
    const targetUrl = decodeURIComponent(req.params.url);
    const response = await fetch(targetUrl);
    const data = await response.json();
    res.json(data);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Frontend usage
fetch('/proxy/https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data));

Solution 3: API Gateway Configuration

Configure CORS at the API gateway level.

AWS API Gateway:

// API Gateway response headers
{
  "Access-Control-Allow-Origin": "https://yourdomain.com",
  "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"
}

Cloudflare Workers:

// cloudflare-worker.js
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const response = await fetch(request);

  // Add CORS headers
  const corsHeaders = {
    'Access-Control-Allow-Origin': 'https://yourdomain.com',
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    'Access-Control-Max-Age': '86400' // 24 hours
  };

  // Handle preflight requests
  if (request.method === 'OPTIONS') {
    return new Response(null, { headers: corsHeaders });
  }

  // Clone response and add CORS headers
  const modifiedResponse = new Response(response.body, response);
  Object.keys(corsHeaders).forEach(key => {
    modifiedResponse.headers.set(key, corsHeaders[key]);
  });

  return modifiedResponse;
}

Solution 4: Development Environment Setup

Configure your development environment to handle CORS properly.

Webpack Dev Server:

// webpack.config.js
module.exports = {
  // ... other config
  devServer: {
    // ✅ Enable CORS for development
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding'
    },
    
    // ✅ Or proxy API requests
    proxy: {
      '/api': {
        target: 'http://localhost:3001',
        changeOrigin: true,
        pathRewrite: {
          '^/api': '', // Remove /api prefix
        },
      },
    },
  },
};

Vite Configuration:

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    proxy: {
      // ✅ Proxy API requests to avoid CORS
      '/api': {
        target: 'http://localhost:3001',
        changeOrigin: true,
        secure: false,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
});

Solution 5: Fetch Configuration Options

Configure fetch requests properly to handle CORS scenarios.

Proper Fetch Configuration:

// ✅ Correct fetch configuration for CORS
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data', {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        // Only include credentials if the server allows it
        // 'Authorization': `Bearer ${token}`,
      },
      // Only include credentials if the server allows it
      // credentials: 'include', // or 'same-origin' or 'omit'
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Fetch error:', error);
    throw error;
  }
}

Handling Credentials:

// ✅ Proper credential handling
async function fetchWithCredentials() {
  try {
    const response = await fetch('https://api.example.com/protected', {
      method: 'GET',
      credentials: 'include', // Include cookies and credentials
      headers: {
        'Content-Type': 'application/json',
      },
    });

    const data = await response.json();
    return data;
  } catch (error) {
    if (error.message.includes('CORS')) {
      console.error('CORS error with credentials - check server configuration');
    }
    throw error;
  }
}

Solution 6: Error Handling and Debugging

Implement proper error handling for CORS issues.

CORS Error Detection:

// ✅ Detect CORS errors specifically
async function safeFetch(url, options = {}) {
  try {
    const response = await fetch(url, options);
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    return response;
  } catch (error) {
    // ✅ Check if it's a CORS error
    if (error.name === 'TypeError' && error.message.includes('fetch')) {
      console.error('CORS error detected:', error.message);
      throw new Error('CORS error: Request blocked by browser security policy');
    }
    
    throw error;
  }
}

// Usage
safeFetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    if (error.message.includes('CORS')) {
      // Handle CORS error specifically
      alert('Unable to fetch data due to CORS policy');
    } else {
      console.error('Other error:', error);
    }
  });

Debugging CORS Issues:

// ✅ CORS debugging utilities
function debugCORS(url) {
  console.log('CORS Debug Information:');
  console.log('Current origin:', window.location.origin);
  console.log('Target URL:', url);
  console.log('Request will be made from:', window.location.href);
  
  // Check if same origin
  const targetUrl = new URL(url);
  const isSameOrigin = 
    targetUrl.origin === window.location.origin;
  
  console.log('Same origin:', isSameOrigin);
  
  if (!isSameOrigin) {
    console.log('⚠️ Cross-origin request detected - CORS headers required');
  }
}

// Usage
debugCORS('https://api.example.com/data');

Solution 7: Alternative Approaches

Use alternative methods when CORS is not configurable.

JSONP (for GET requests only):

// ✅ JSONP as CORS workaround (only for GET requests)
function jsonp(url, callback) {
  const script = document.createElement('script');
  const callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());
  
  window[callbackName] = function(data) {
    delete window[callbackName];
    document.head.removeChild(script);
    callback(data);
  };
  
  script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'callback=' + callbackName;
  document.head.appendChild(script);
}

// Usage (only works if the API supports JSONP)
jsonp('https://api.example.com/data', function(data) {
  console.log('JSONP response:', data);
});

Server-Side Proxy:

// ✅ Server-side proxy approach
// Instead of client-side fetch, make request through your own server
async function fetchViaProxy(proxyEndpoint, targetUrl) {
  const response = await fetch(proxyEndpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ url: targetUrl })
  });
  
  return response.json();
}

// Backend proxy endpoint
app.post('/api/proxy', async (req, res) => {
  try {
    const { url } = req.body;
    const response = await fetch(url);
    const data = await response.json();
    res.json(data);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

Solution 8: Framework-Specific Solutions

Handle CORS in different JavaScript frameworks.

React with Proxy:

// setupProxy.js (for Create React App)
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:3001',
      changeOrigin: true,
      pathRewrite: {
        '^/api': '',
      },
    })
  );
};

Angular with Proxy:

// proxy.conf.json
{
  "/api/*": {
    "target": "http://localhost:3001",
    "secure": false,
    "changeOrigin": true,
    "logLevel": "debug"
  }
}

// angular.json
{
  "projects": {
    "your-app": {
      "architect": {
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "proxyConfig": "proxy.conf.json"
          }
        }
      }
    }
  }
}

Performance Considerations

Optimized CORS Requests:

// ✅ Optimized CORS handling
class CORSEnhancedAPI {
  constructor(baseURL) {
    this.baseURL = baseURL;
    this.cache = new Map();
  }

  async get(endpoint, options = {}) {
    const cacheKey = `${endpoint}?${JSON.stringify(options)}`;
    
    // ✅ Check cache first
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey);
    }

    try {
      const response = await fetch(`${this.baseURL}${endpoint}`, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
          ...options.headers,
        },
        ...options,
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      const data = await response.json();
      
      // ✅ Cache successful responses
      this.cache.set(cacheKey, data);
      
      return data;
    } catch (error) {
      if (error.message.includes('CORS')) {
        console.error('CORS error in API class:', error);
      }
      throw error;
    }
  }
}

// Usage
const api = new CORSEnhancedAPI('https://api.example.com');

Security Considerations

Secure CORS Configuration:

// ✅ Secure CORS implementation
function createSecureCORSConfig(allowedOrigins) {
  return {
    origin: (origin, callback) => {
      // ✅ Check if origin is in allowed list
      if (!origin || allowedOrigins.includes(origin)) {
        callback(null, true);
      } else {
        callback(new Error('Not allowed by CORS'));
      }
    },
    credentials: true,
    optionsSuccessStatus: 200,
    // ✅ Only allow necessary methods
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
    // ✅ Only allow necessary headers
    allowedHeaders: [
      'Content-Type', 
      'Authorization', 
      'X-Requested-With',
      'Accept',
      'Origin'
    ]
  };
}

// Usage
const corsOptions = createSecureCORSConfig([
  'https://yourdomain.com',
  'https://www.yourdomain.com'
]);

Common Mistakes to Avoid

1. Using Wildcard in Production:

// ❌ Don't do this in production
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*'); // Security risk
  next();
});

2. Forgetting Preflight Requests:

// ❌ Don't forget to handle OPTIONS requests
app.options('*', (req, res) => {
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.sendStatus(200);
});

3. Incorrect Header Names:

// ❌ Don't use incorrect header names
res.header('Access-Control-Allow-Origin', 'https://example.com'); // Must match exactly

Alternative Solutions

Using React DevTools:

// Component with CORS debugging
function CORSDebugComponent() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch('/api/data')
      .then(response => response.json())
      .then(setData)
      .catch(err => {
        setError(err.message);
        console.error('CORS Debug:', err);
      });
  }, []);

  return (
    <div data-testid="cors-debug">
      {error && <div>Error: {error}</div>}
      {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
    </div>
  );
}

Feature Detection:

// Check for CORS support
function checkCORSSupport() {
  return typeof fetch !== 'undefined';
}

// CORS capability check
function canMakeCrossOriginRequests() {
  try {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'https://httpbin.org/get', true);
    return true;
  } catch (e) {
    return false;
  }
}

Troubleshooting Checklist

When encountering CORS errors:

  1. Check Server Headers: Verify server sends proper CORS headers
  2. Verify Origins: Ensure origin matches allowed origins exactly
  3. Test Preflight: Check if OPTIONS requests are handled
  4. Review Credentials: Confirm credential handling is correct
  5. Check Port/Protocol: Verify scheme, host, and port match
  6. Test with Proxy: Try using a proxy to isolate the issue
  7. Review Browser Console: Look for detailed CORS error messages

Conclusion

The ‘Access to fetch blocked by CORS policy’ error occurs due to browser security restrictions on cross-origin requests. By implementing proper server-side CORS configuration, using development proxies, or alternative approaches, you can resolve these errors and ensure your applications can make necessary cross-origin requests.

The key to resolving CORS errors is understanding the same-origin policy, implementing proper server configuration, and using appropriate workarounds when server access isn’t available. Whether you’re working with REST APIs, microservices, or third-party services, the solutions provided in this guide will help you handle CORS issues effectively.

Remember to always configure CORS securely in production, handle errors gracefully, and test your cross-origin requests thoroughly to ensure smooth operation across different environments.

Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

Javascript

Fix: CORS policy: No 'Access-Control-Allow-Origin' Error in Node & Javascript

Learn how to fix the 'CORS policy: No Access-Control-Allow-Origin' error in JavaScript and Node.js applications. This comprehensive guide covers CORS configuration, headers, and best practices.

January 2, 2026
Javascript

Fix: fetch failed or TypeError: Failed to fetch error in JavaScript

Learn how to fix the 'fetch failed' and 'TypeError: Failed to fetch' errors in JavaScript applications. This comprehensive guide covers network issues, CORS, and best practices.

January 2, 2026
Javascript

How to Handle & Fix Failed to resolve import Error Tutorial

Learn how to fix 'failed to resolve import' errors in JavaScript. Complete guide with solutions for ES6 modules, Node.js, and bundler configurations.

January 2, 2026