Tutorials Logic, IN info@tutorialslogic.com

CORS in AJAX Cross Origin Requests: Causes and Fixes

What is CORS?

CORS (Cross-Origin Resource Sharing) is a browser security mechanism that controls how web pages can request resources from a different origin (domain, protocol, or port) than the one that served the page.

The Same-Origin Policy (SOP) is the underlying rule: by default, a script on https://app.example.com cannot make AJAX requests to https://api.other.com. CORS is the standard way to relax this restriction in a controlled manner.

An "origin" is defined as the combination of: protocol + hostname + port. Any difference makes it cross-origin.

CORS Headers

Header Direction Purpose
Access-Control-Allow-Origin Response Which origins are allowed (* or specific origin)
Access-Control-Allow-Methods Response Allowed HTTP methods (GET, POST, PUT, DELETE)
Access-Control-Allow-Headers Response Allowed request headers
Access-Control-Allow-Credentials Response Whether cookies/auth headers are allowed
Access-Control-Max-Age Response How long to cache preflight results (seconds)
Origin Request The origin of the requesting page

Enabling CORS in PHP

Enabling CORS in PHP
<?php
// api.php - Enable CORS headers

// Allow a specific origin (recommended over *)
$allowedOrigins = ['https://app.example.com', 'https://www.example.com'];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';

if (in_array($origin, $allowedOrigins)) {
    header("Access-Control-Allow-Origin: $origin");
} else {
    // Or allow all origins (less secure, fine for public APIs)
    // header('Access-Control-Allow-Origin: *');
}

header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
header('Access-Control-Allow-Credentials: true'); // required for cookies/auth
header('Access-Control-Max-Age: 86400');           // cache preflight for 24 hours

// Handle preflight OPTIONS request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204); // No Content
    exit;
}

// Continue with normal request handling...
header('Content-Type: application/json');
echo json_encode(['message' => 'CORS-enabled response']);
?>

Simple vs Preflight Requests

Simple requests do not trigger a preflight. They must use GET, HEAD, or POST with only safe headers (Content-Type: application/x-www-form-urlencoded, multipart/form-data, or text/plain).

Preflight requests are automatically sent by the browser as an HTTP OPTIONS request before the actual request. They occur when the request uses a non-simple method (PUT, DELETE, PATCH), a non-simple Content-Type (like application/json), or custom headers (like Authorization).

Enabling CORS in Node.js / Express

Enabling CORS in Node.js / Express
// npm install cors
const express = require('express');
const cors = require('cors');
const app = express();

// Option 1: Allow all origins (public API)
app.use(cors());

// Option 2: Allow specific origins with full config
app.use(cors({
  origin: ['https://app.example.com', 'https://www.example.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,   // allow cookies and auth headers
  maxAge: 86400        // cache preflight for 24 hours
}));

// Option 3: Dynamic origin validation
app.use(cors({
  origin: function (origin, callback) {
    const whitelist = ['https://app.example.com'];
    if (!origin || whitelist.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  }
}));

app.get('/api/data', (req, res) => {
  res.json({ message: 'CORS-enabled response' });
});

app.listen(3000);

Proxy Approach and JSONP (Legacy)

Proxy Approach and JSONP (Legacy)
// ---- PROXY APPROACH (recommended modern solution) ----
// Your own server proxies the request to the third-party API
// Client -> Your Server -> Third-Party API -> Your Server -> Client
// No CORS issue because the server-to-server call is not browser-restricted

// Client code (calls your own server)
fetch('/proxy/weather?city=London')
  .then(res => res.json())
  .then(data => console.log(data));

// Your server (proxy.php or Express route) forwards to the real API:
// $response = file_get_contents("https://api.weather.com/v1/city=London&key=SECRET");
// echo $response;

// ---- JSONP (legacy - only GET, avoid in new code) ----
// JSONP works by injecting a <script> tag - not a real AJAX request
// The server wraps the response in a callback function call

function handleWeatherData(data) {
  console.log('Temperature:', data.temp);
}

// Dynamically create a script tag
const script = document.createElement('script');
script.src = 'https://api.example.com/weather?city=London&callback=handleWeatherData';
document.head.appendChild(script);
// Server responds with: handleWeatherData({"temp": 22, "city": "London"})
// The browser executes it as JavaScript, calling our function

// NOTE: JSONP is a security risk and only supports GET.
// Use CORS or a proxy instead.
Before you move on

CORS in AJAX Cross Origin Requests: Causes and Fixes Mastery Check

5 checks
  • The Same-Origin Policy (SOP) is the underlying rule: by default, a script on https://app.example.com cannot make AJAX requests to https://api.other.com.
  • CORS is the standard way to relax this restriction in a controlled manner.
  • An "origin" is defined as the combination of: protocol + hostname + port.
  • Simple requests do not trigger a preflight.
  • They must use GET, HEAD, or POST with only safe headers (Content-Type: application/x-www-form-urlencoded, multipart/form-data, or text/plain).
Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.