CORS (Cross-Origin Resource Sharing) errors show up specifically when a browser-based frontend on one origin (like app.example.com) calls a Laravel API on a different origin (api.example.com) — Laravel ships with CORS support built in via a dedicated config file, not a package that needs separate installation on modern versions.
The CORS configuration file
// config/cors.php
return [
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['https://app.example.com'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
Restricting which routes CORS applies to
'paths' => ['api/*', 'sanctum/csrf-cookie'],
paths restricts CORS handling to only the routes matching these patterns — typically just the API routes, since a same-origin traditional web page being served doesn't need CORS headers at all, and unnecessarily applying them site-wide is pointless overhead.
Specifying allowed origins explicitly
'allowed_origins' => ['https://app.example.com', 'https://admin.example.com'],
Explicitly listing each legitimate frontend origin allowed to call the API is the safer approach — the browser only allows the cross-origin request through if the responding Access-Control-Allow-Origin header matches the requesting page's actual origin.
The wildcard origin, and why it's usually the wrong choice for an authenticated API
'allowed_origins' => ['*'], // allows any origin
'*' allows literally any website to make cross-origin requests to the API — acceptable for a genuinely public, unauthenticated API (like open weather data), but it cannot be combined with supports_credentials: true at all (browsers actively block this combination) — meaning it's incompatible with cookie-based authentication like Sanctum's SPA authentication.
Enabling credentials (cookies) for a cross-origin request
'supports_credentials' => true,
'allowed_origins' => ['https://app.example.com'], // must be specific, not '*'
// On the frontend fetch call
fetch('https://api.example.com/user', {
credentials: 'include'
});
supports_credentials: true is required for cookie-based cross-origin authentication (like Sanctum's SPA mode) to work at all — and it specifically requires an exact origin list rather than the * wildcard, a deliberate browser-level security restriction that Laravel's config can't override.
Understanding the preflight OPTIONS request
For anything beyond a "simple" request (a custom header, a non-GET/POST method, a JSON content type), the browser automatically sends a preliminary OPTIONS request first, checking whether the actual request is allowed before sending it — Laravel's CORS middleware handles responding to this preflight request automatically; no manual route or controller handling for OPTIONS is needed.
Why a CORS error is a browser-only restriction, not a server-side one
CORS is entirely enforced by the browser itself, not the server — a tool like Postman, curl, or a server-to-server request from another backend is completely unaffected by CORS configuration, since only an actual browser executing JavaScript from a web page enforces this restriction; this is precisely why "it works in Postman but not from my frontend" is a classic CORS symptom, not a sign of a broken endpoint.