{
    "slug": "cors",
    "term": "CORS — Cross-Origin Resource Sharing",
    "category": "security",
    "difficulty": "intermediate",
    "short": "A browser security mechanism that blocks JavaScript from making HTTP requests to a different origin — PHP APIs must send specific headers to allow cross-origin requests from permitted frontend origins.",
    "long": "The Same-Origin Policy prevents JavaScript from making requests to a different domain, protocol, or port than the page it is running on. CORS is the controlled mechanism for relaxing this restriction. For simple requests (GET, POST with certain content types), the browser adds an Origin header; the server responds with Access-Control-Allow-Origin and the browser either allows or blocks the response. For complex requests (PUT, DELETE, custom headers, JSON content-type), the browser sends a preflight OPTIONS request first to check permissions; the server must respond with Access-Control-Allow-Methods, Access-Control-Allow-Headers, and optionally Access-Control-Max-Age. In PHP APIs, CORS headers must be set on every response including error responses. Wildcard (*) for Access-Control-Allow-Origin is only appropriate for public APIs — for APIs that use cookies or Authorization headers, the specific origin must be listed and Access-Control-Allow-Credentials: true must be set.",
    "aliases": [
        "Cross-Origin Resource Sharing",
        "CORS headers",
        "preflight request",
        "Access-Control-Allow-Origin",
        "same-origin policy"
    ],
    "tags": [
        "cors",
        "security",
        "http",
        "api",
        "php",
        "headers",
        "browser"
    ],
    "misconception": "Setting Access-Control-Allow-Origin: * fixes all CORS errors. Wildcard (*) cannot be used when credentials (cookies, Authorization headers) are involved. When the frontend sends credentials, the server must specify the exact allowed origin, not *, and must set Access-Control-Allow-Credentials: true. A CORS error with credentials will not be fixed by a wildcard — it requires the specific origin to be allowlisted.",
    "why_it_matters": "CORS errors are among the most common issues PHP API developers encounter when building frontends separately from backends. Understanding CORS prevents hours of debugging what looks like a server error but is a browser security block. More importantly, CORS misconfiguration is a security risk — a PHP API that allows all origins with credentials enabled (Access-Control-Allow-Origin: * with Allow-Credentials: true) allows any website to make authenticated requests on behalf of users visiting that malicious site.",
    "common_mistakes": [
        "Not handling OPTIONS preflight requests — complex requests get a preflight that must return 200 with CORS headers, not a 405 Method Not Allowed.",
        "Setting CORS headers only on success responses — error responses (4xx, 5xx) must also include CORS headers or the browser hides the error from the JavaScript.",
        "Using Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true — browsers reject this combination; specify the exact origin.",
        "Setting CORS headers in application middleware only — some PHP frameworks handle OPTIONS at the router level before middleware runs; handle it earlier."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "csrf",
        "authentication",
        "http_caching",
        "refused_bequest"
    ],
    "prerequisites": [],
    "refs": [
        "https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"
    ],
    "bad_code": "// Missing preflight handling — CORS errors on all complex requests\nheader('Access-Control-Allow-Origin: *');\n// No OPTIONS handling — preflight fails with 404/405\n// With credentials — wildcard + credentials = browser rejection",
    "good_code": "// Handle preflight + correct headers\nfunction setCorsHeaders(string $allowedOrigin): void {\n    $origin = $_SERVER['HTTP_ORIGIN'] ?? '';\n    if ($origin === $allowedOrigin) {\n        header('Access-Control-Allow-Origin: ' . $origin);\n        header('Vary: Origin'); // important for caching\n    }\n    header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');\n    header('Access-Control-Allow-Headers: Content-Type, Authorization, X-CSRF-Token');\n    header('Access-Control-Allow-Credentials: true');\n    header('Access-Control-Max-Age: 86400'); // cache preflight 24hrs\n}\n\n// Handle preflight before routing\nif ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {\n    setCorsHeaders('https://app.example.com');\n    http_response_code(200);\n    exit;\n}",
    "quick_fix": "Use a CORS middleware that handles OPTIONS preflight automatically. For PHP APIs: respond to OPTIONS with 200 and the correct headers before routing; allowlist specific origins rather than using *",
    "severity": "medium",
    "effort": "low",
    "created": "2026-03-23",
    "updated": "2026-04-05",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/cors",
        "html_url": "https://codeclaritylab.com/glossary/cors",
        "json_url": "https://codeclaritylab.com/glossary/cors.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[CORS — Cross-Origin Resource Sharing](https://codeclaritylab.com/glossary/cors) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/cors"
            }
        }
    }
}