CORS (Cross-Origin Resource Sharing) errors show up specifically when a frontend running on one origin — a different domain, subdomain, or port than the API — tries to call that API from JavaScript in the browser. It's a browser-enforced security restriction, not a server error in the usual sense: the request often reaches the Laravel app fine, but the browser blocks the frontend JavaScript from reading the response unless the server's headers explicitly allow it.
1. Laravel ships CORS support out of the box
Since Laravel 7, a CORS middleware and its config file are included by default — no third-party package is needed for standard cases. The config lives at config/cors.php:
return [
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['https://app.example.com'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
2. paths — which routes CORS applies to
Only requests matching one of these path patterns get CORS headers at all — by default, that's everything under /api/* plus Sanctum's CSRF cookie route. A route outside those paths making cross-origin requests won't have CORS headers added, even if allowed_origins would otherwise permit it.
3. allowed_origins — never use '*' with credentials
'allowed_origins' => ['https://app.example.com', 'https://admin.example.com'],
A wildcard ('*') allows any origin whatsoever to make requests — acceptable for a fully public, read-only API with no authentication, but a real security risk for anything involving cookies, sessions, or authenticated requests. Browsers actively refuse the combination of a wildcard origin with supports_credentials: true for exactly this reason; listing specific allowed origins explicitly is the correct approach for any authenticated API.
4. supports_credentials — needed for cookie-based auth
'supports_credentials' => true,
If the frontend sends cookies (session-based auth, Sanctum's SPA authentication) along with cross-origin requests, this needs to be true on the Laravel side — and the frontend's HTTP client needs to explicitly opt in as well (credentials: 'include' in fetch, or withCredentials: true in Axios). Missing either half of this pairing is a common reason cookies silently don't get sent even with CORS otherwise configured correctly.
5. Preflight requests
For anything beyond a simple GET — a POST with a JSON body, a custom header, a PUT or DELETE — the browser first sends an automatic OPTIONS "preflight" request to check whether the actual request is allowed, before sending the real one. Laravel's CORS middleware handles responding to these automatically; the app's own routes don't need an explicit OPTIONS handler for this to work.
6. A CORS error in the browser console doesn't mean the server is broken
The most common confusion: the request often actually reaches the Laravel application and gets processed successfully — the browser is what refuses to hand the response back to the calling JavaScript. Checking Laravel's own logs for a request that "isn't working" due to CORS is usually a dead end, since nothing failed on the server side at all.