fruitcake/laravel-cors
Laravel middleware to handle Cross-Origin Resource Sharing (CORS). Configure allowed origins, methods, headers, credentials, and exposed headers via a config file. Adds proper CORS response headers and supports preflight OPTIONS requests for APIs and SPAs.
Install the package
composer require fruitcake/laravel-cors
Note: The package is archived but still used in many legacy and active Laravel apps (v6–v9).
Publish the config
php artisan vendor:publish --tag=cors
This creates config/cors.php with sensible defaults (e.g., allowedOrigins => ['*'], allowedMethods => ['*']).
Register middleware globally
In app/Http/Kernel.php, add the middleware to the web and/or api middleware groups:
protected $middlewareGroups = [
'web' => [
// ...
\Fruitcake\Cors\HandleCors::class,
],
'api' => [
// ...
\Fruitcake\Cors\HandleCors::class,
],
];
First use case: Allow a frontend SPA (e.g., Vue/React dev server at http://localhost:3000) to call your Laravel API. By default, allowedOrigins => ['*'] works for development—but do not use * in production.
Per-environment config via .env
Use config/cors.php with environment-specific origin rules:
'allowed_origins' => explode(',', env('CORS_ORIGINS', '*')),
'allowed_origins_patterns' => explode(',', env('CORS_ORIGINS_PATTERNS', '')),
Then set .env:
CORS_ORIGINS=https://app.production.com,https://staging.app.com
CORS_ORIGINS_PATTERNS=^https://.*\.staging\.
Targeted path matching
Configure paths to limit CORS to specific API prefixes (e.g., only /api/*):
'paths' => ['api/*', 'sanctum/csrf-cookie'],
Avoids CORS headers on GET / or health checks.
Custom preflight response (CORS OPTIONS requests)
By default, the middleware handles preflight silently. To inspect/debug:
// In config/cors.php
'max_age' => 86400,
'supports_credentials' => true, // Required for cookies/auth
'exposed_headers' => ['X-My-Custom-Header'],
Use in Lumen (pre-v2.0 breaking change legacy)
For older Lumen apps, avoid manual cors config—just register Fruitcake\Cors\HandleCors::class in app/Http/Kernel.php (config auto-loads).
Archived, but stable
Last release was 2022-02-23 and repo is archived, but the core logic is stable. It depends on fruitcake/php-cors (not asm89/stack-cors since v2.1.0). No active maintenance ≠ unmaintained—many apps run it reliably in production.
supports_credentials + allowed_origins => ['*'] is invalid
Laravel throws a config exception at boot if both are set. Use explicit origins instead:
// ❌ Invalid
'supports_credentials' => true,
'allowed_origins' => ['*'],
// ✅ Valid
'allowed_origins' => ['https://trusted.app'],
'supports_credentials' => true,
Debugging CORS issues
Vary: Origin in responses (critical for cache proxies).curl -i -H "Origin: http://localhost:3000" http://your-api.com/api/test to see headers.config/cors.php:
'debug' => env('APP_DEBUG', false),
Octane / swoole workers
Early versions (pre-2.0.4) had memory leaks in Octane. Ensure you’re on ≥ v0.11.0 (uses fruitcake/php-cors ≥ v1.2). The middleware is stateless, so this is safe in workers.
Wildcard patterns
Since v0.11.0, use allowedOriginPatterns for regex (e.g., ['^https://dev-.*\.example\.com$']) and simple wildcards (*.example.com) in allowedOrigins. Avoid mixing both unnecessarily.
Don’t use in web group by default
Unless your web routes serve JSON or are consumed cross-origin, CORS overhead is unnecessary. Prefer api group only unless needed elsewhere.
Cache busting tip
When changing CORS config, run php artisan config:clear—some reverse proxies (e.g., Cloudflare) cache 401/403 + CORS headers tightly.
How can I help you explore Laravel packages today?