Reader Stacks

How to Enable CORS in a Laravel or PHP API

A browser blocks cross-origin requests by default — CORS headers on the server are what explicitly permit a specific frontend origin to actually call your API.

CORS (Cross-Origin Resource Sharing) errors happen when a browser blocks a JavaScript request from one origin (say, app.example.com) to an API on a different origin (api.example.com) — this is a genuine browser security restriction, and the fix lives entirely on the server side: sending headers that explicitly permit the calling origin.

Laravel's built-in CORS configuration

// config/cors.php
return [
    'paths' => ['api/*'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['https://app.example.com'],
    'allowed_headers' => ['*'],
    'supports_credentials' => false,
];

Modern Laravel ships with a CORS middleware already applied to the api middleware group by default — the actual work needed is usually just editing config/cors.php to list your real frontend origin(s), rather than writing any CORS-handling code from scratch.

Why allowed_origins shouldn't just be a wildcard in production

'allowed_origins' => ['*'], // permissive, generally not appropriate for a production API with credentials

A wildcard origin is convenient for local development, but for a production API — especially one using cookies or authentication headers — listing the actual specific frontend origin(s) is the safer choice, and is in fact required by the CORS specification itself once supports_credentials is true (browsers reject a wildcard origin combined with credentialed requests outright).

Enabling credentialed requests (cookies, Authorization headers)

'supports_credentials' => true,
// on the frontend, fetch() needs this too
fetch('https://api.example.com/user', {
    credentials: 'include',
})

Both sides need to agree — the server's CORS config allowing credentials, and the frontend's request explicitly including them — for cookie-based cross-origin authentication to work at all.

Handling CORS manually in plain PHP (without Laravel)

Handling the OPTIONS method explicitly is necessary because browsers send a "preflight" OPTIONS request before certain cross-origin requests (like a POST with a JSON content type), checking the CORS headers before sending the real request — without responding successfully to this preflight, the browser never sends the actual request at all.

Debugging a CORS error

The browser's console error message for a CORS failure names the specific missing or mismatched header — checking that error message against the server's actual response headers (via browser dev tools' Network tab, not just the request) is the fastest way to identify exactly which part of the CORS configuration is missing or incorrect.