CORS Configuration Problems | Blue Frog Docs

CORS Configuration Problems

Diagnose and fix Cross-Origin Resource Sharing (CORS) errors that block API requests and third-party integrations

CORS Configuration Problems

What This Means

Cross-Origin Resource Sharing (CORS) is a security mechanism that controls how web pages from one domain can access resources from another domain. CORS errors occur when browsers block cross-origin requests due to missing or incorrect CORS headers, preventing your frontend from communicating with APIs, loading fonts, or integrating third-party services.

Common CORS Problems

Missing CORS Headers:

  • No Access-Control-Allow-Origin header
  • Headers not sent from API/server
  • Wrong header format or values
  • Headers missing for preflight requests

Configuration Errors:

  • Wildcard * with credentials
  • Wrong origin specified
  • Missing allowed methods/headers
  • Preflight requests failing

Common Error Messages:

Access to fetch at 'https://api.example.com' from origin 'https://example.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is
present on the requested resource.

Access to XMLHttpRequest has been blocked by CORS policy: Response to preflight
request doesn't pass access control check: No 'Access-Control-Allow-Origin'
header is present on the requested resource.

Impact on Your Business

Functionality Breaks:

  • API calls fail completely
  • Forms don't submit
  • Data doesn't load
  • Third-party integrations broken
  • Fonts don't load (slow fallback fonts)

User Experience:

  • Features appear broken
  • Error messages shown to users
  • Page functionality missing
  • Slow page loads (font fallback)

Business Impact:

  • Lost conversions from broken forms
  • Customer frustration
  • Support tickets increase
  • Revenue loss from broken features
  • Abandoned integrations

Development:

  • Delayed deployments
  • Complex workarounds needed
  • Testing difficulties
  • Security vulnerabilities if misconfigured

How to Diagnose

  1. Open DevTools (F12)
  2. Navigate to "Console" tab
  3. Trigger the failing request
  4. Look for CORS error messages

What to Look For:

Access to fetch at 'https://api.example.com/data' from origin
'https://mysite.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on
the requested resource.

Method 2: Network Tab Analysis

  1. Open DevTools → "Network" tab
  2. Make the failing request
  3. Click on failed request
  4. Check "Headers" tab

What to Look For:

  • Status Code: 200 but CORS error
  • Missing Access-Control-Allow-Origin in Response Headers
  • OPTIONS request (preflight) failing

Response Headers should include:

Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

Method 3: cURL Testing

Test from command line:

# Simple request
curl -H "Origin: https://example.com" \
     -H "Access-Control-Request-Method: POST" \
     -H "Access-Control-Request-Headers: Content-Type" \
     -X OPTIONS \
     --verbose \
     https://api.example.com/endpoint

# Look for headers in response

What to Look For:

  • HTTP 200 OK for OPTIONS
  • CORS headers in response
  • Correct origin in Allow-Origin

Method 4: Online CORS Testers

  1. Visit test-cors.org
  2. Enter your API endpoint
  3. Test different origins
  4. Review results

What to Look For:

  • Which origins are allowed
  • Which methods are allowed
  • Whether credentials are supported

Method 5: Check Preflight Requests

Preflight requests happen for:

  • POST/PUT/PATCH/DELETE methods
  • Custom headers (Authorization, etc.)
  • Content-Type other than form data

In Network tab:

  • Look for OPTIONS request before actual request
  • OPTIONS must return 200
  • Must include CORS headers

General Fixes

Fix 1: Configure Server CORS Headers

Express.js (Node.js):

const express = require('express');
const cors = require('cors');
const app = express();

// Simple usage - allow all origins (development only)
app.use(cors());

// Production - specific origins
app.use(cors({
  origin: 'https://example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400 // 24 hours
}));

// Multiple origins
const allowedOrigins = [
  'https://example.com',
  'https://www.example.com',
  'https://staging.example.com'
];

app.use(cors({
  origin: function(origin, callback) {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true
}));

Manual headers (Express.js):

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://example.com');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.header('Access-Control-Allow-Credentials', 'true');

  // Handle preflight
  if (req.method === 'OPTIONS') {
    res.sendStatus(200);
  } else {
    next();
  }
});

Fix 2: Configure Apache CORS

Apache (.htaccess):

<IfModule mod_headers.c>
  # Allow from specific origin
  Header set Access-Control-Allow-Origin "https://example.com"

  # Allow credentials
  Header set Access-Control-Allow-Credentials "true"

  # Allowed methods
  Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"

  # Allowed headers
  Header set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With"

  # Preflight cache
  Header set Access-Control-Max-Age "86400"
</IfModule>

# Handle preflight OPTIONS requests
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REQUEST_METHOD} OPTIONS
  RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>

Multiple origins:

<IfModule mod_headers.c>
  SetEnvIf Origin "^https://(www\.)?example\.com$" ORIGIN=$0
  SetEnvIf Origin "^https://staging\.example\.com$" ORIGIN=$0

  Header always set Access-Control-Allow-Origin "%{ORIGIN}e" env=ORIGIN
  Header always set Access-Control-Allow-Credentials "true" env=ORIGIN
  Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" env=ORIGIN
  Header always set Access-Control-Allow-Headers "Content-Type, Authorization" env=ORIGIN
</IfModule>

Fix 3: Configure Nginx CORS

Nginx configuration:

# Add CORS headers
location /api/ {
  # Simple requests
  add_header 'Access-Control-Allow-Origin' 'https://example.com' always;
  add_header 'Access-Control-Allow-Credentials' 'true' always;
  add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
  add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;

  # Preflight requests
  if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' 'https://example.com';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
    add_header 'Access-Control-Max-Age' 86400;
    add_header 'Content-Type' 'text/plain charset=UTF-8';
    add_header 'Content-Length' 0;
    return 204;
  }

  proxy_pass http://backend;
}

Multiple origins:

map $http_origin $cors_origin {
  default "";
  "~^https://(www\.)?example\.com$" $http_origin;
  "~^https://staging\.example\.com$" $http_origin;
}

location /api/ {
  if ($cors_origin != "") {
    add_header 'Access-Control-Allow-Origin' $cors_origin always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
  }

  # ... rest of config
}

Fix 4: Handle Credentials Properly

Cannot use wildcard with credentials:

// Wrong - doesn't work
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', 'true');

// Correct - specific origin
res.header('Access-Control-Allow-Origin', 'https://example.com');
res.header('Access-Control-Allow-Credentials', 'true');

// Or dynamically match origin
const allowedOrigins = ['https://example.com', 'https://staging.example.com'];
if (allowedOrigins.includes(req.headers.origin)) {
  res.header('Access-Control-Allow-Origin', req.headers.origin);
  res.header('Access-Control-Allow-Credentials', 'true');
}

Client-side (fetch):

// Include credentials
fetch('https://api.example.com/data', {
  method: 'POST',
  credentials: 'include', // Important!
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
});

Fix 5: Fix Preflight Request Issues

Ensure OPTIONS requests succeed:

// Express.js
app.options('*', cors()); // Enable preflight for all routes

// Or manually handle OPTIONS
app.use((req, res, next) => {
  if (req.method === 'OPTIONS') {
    res.header('Access-Control-Allow-Origin', 'https://example.com');
    res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    res.header('Access-Control-Max-Age', '86400');
    return res.sendStatus(200);
  }
  next();
});

Fix 6: Use Proxy for Development

Development proxy to avoid CORS:

React (package.json):

{
  "proxy": "http://localhost:3001"
}

Vue (vue.config.js):

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3001',
        changeOrigin: true
      }
    }
  }
};

Webpack:

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3001',
        pathRewrite: {'^/api': ''},
        changeOrigin: true
      }
    }
  }
};

Fix 7: Use CORS Proxy (Last Resort)

Only for development/testing:

// Using cors-anywhere or similar
const API_URL = process.env.NODE_ENV === 'production'
  ? 'https://api.example.com'
  : 'https://cors-anywhere.herokuapp.com/https://api.example.com';

fetch(`${API_URL}/data`)
  .then(res => res.json())
  .then(data => console.log(data));

Note: Don't rely on third-party CORS proxies in production!

Platform-Specific Guides

Detailed implementation instructions for your specific platform:

Platform Troubleshooting Guide
Shopify Shopify CORS Guide
WordPress WordPress CORS Guide
Wix Wix CORS Guide
Squarespace Squarespace CORS Guide
Webflow Webflow CORS Guide

Verification

After fixing CORS issues:

  1. Browser console:

    • No CORS errors
    • Requests succeed
    • Data loads properly
  2. Network tab:

    • 200 OK status
    • CORS headers present
    • OPTIONS requests succeed
  3. Test all scenarios:

    • Simple GET requests
    • POST with JSON
    • Requests with credentials
    • Custom headers
  4. Test from production domain:

    • Not just localhost
    • Verify actual domain works
  5. Cross-browser testing:

    • Chrome, Firefox, Safari
    • Mobile browsers

Common Mistakes

  1. Using wildcard with credentials - Doesn't work
  2. Only allowing localhost - Production breaks
  3. Missing preflight handling - OPTIONS requests fail
  4. Wrong origin format - Include protocol and port
  5. Not testing with credentials - Different configuration needed
  6. Allowing all origins in production - Security risk
  7. Missing headers on errors - CORS headers needed on all responses
  8. Case sensitivity - Headers are case-insensitive but origins aren't
  9. Not caching preflight - Performance impact
  10. Relying on CORS proxies - Not a production solution

Additional Resources

// SYS.FOOTER