spatie/laravel-cors
Adds configurable CORS support to Laravel/Lumen: sets CORS headers on responses, handles preflight requests, and lets you define allowed origins, methods, headers, and credentials via middleware and config. Abandoned since Laravel 7+ has native CORS support.
Installation:
composer require spatie/laravel-cors
The package auto-registers its service provider (Spatie\Cors\CorsServiceProvider) and publishes a config file (config/cors.php) via:
php artisan vendor:publish --provider="Spatie\Cors\CorsServiceProvider"
Middleware Registration:
Add the Spatie\Cors\Cors middleware to your $middleware array in app/Http/Kernel.php (for global CORS) or to specific routes/middleware groups.
First Use Case:
Configure config/cors.php to allow your frontend domain (e.g., paths => ['api/*'], allowed_methods => ['*'], allowed_origins => ['http://your-frontend.com']).
Test with a simple API endpoint (e.g., GET /api/test) and verify CORS headers in browser dev tools (Access-Control-Allow-Origin).
Global CORS Configuration:
Use config/cors.php to define default rules (e.g., allowed origins, methods, headers, credentials). Example:
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
'allowed_origins' => ['https://your-app.com', 'https://staging.your-app.com'],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
Route-Specific Overrides: Dynamically override CORS settings for specific routes using middleware parameters:
Route::middleware(['cors:http://custom-origin.com'])->group(function () {
// Routes here use custom origin
});
Or pass an array of options:
Route::middleware(['cors:api', 'auth:sanctum'])->get('/protected', function () {
return response()->json(['data' => 'protected']);
});
Preflight Requests (OPTIONS):
The package automatically handles OPTIONS requests for configured paths. Ensure OPTIONS is included in allowed_methods and test with:
curl -X OPTIONS -H "Origin: http://your-frontend.com" http://your-api.com/api/test
Integration with Sanctum/Passport:
Combine with spatie/laravel-sanctum or laravel/passport by adding Sanctum’s middleware after CORS:
$middlewareGroups['api'] = [
\Spatie\Cors\Cors::class,
'throttle:api',
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'auth:sanctum',
];
Dynamic Origin Handling:
Use a closure in allowed_origins to dynamically validate origins (e.g., for multi-tenant apps):
'allowed_origins' => function ($request) {
return ['https://' . $request->tenant->domain];
},
Middleware Order:
VerifyCsrfToken if using Sanctum, as CSRF tokens may not be accessible during preflight.Preflight Failures:
OPTIONS requests return 405 Method Not Allowed, ensure:
OPTIONS is in allowed_methods.OPTIONS requests. Use:
Route::options('/api/test', function () {});
\Log::info('Preflight request', ['method' => $request->method(), 'headers' => $request->header()]);
Credentials Flag:
supports_credentials: true, ensure:
withCredentials.allowed_origins does not use * (must list specific domains).Access-Control-Allow-Credentials: true.Caching Headers:
max_age in seconds controls how long browsers cache preflight responses. Set to 0 for dynamic origins or high values (e.g., 86400) for static setups.Lumen Specifics:
bootstrap/app.php:
$app->middleware(Spatie\Cors\Cors::class);
Inspect Headers:
Use curl or browser dev tools to verify headers:
curl -I -H "Origin: http://frontend.com" http://api.com/api/test
Expected headers:
Access-Control-Allow-Origin: http://frontend.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Logging:
Enable debug logging in config/cors.php:
'debug' => env('CORS_DEBUG', false),
Logs will appear in storage/logs/laravel.log.
Testing: Use Laravel’s HTTP tests to assert CORS headers:
$response = $this->get('/api/test');
$response->assertHeader('Access-Control-Allow-Origin', 'http://frontend.com');
Custom Middleware: Extend the base middleware by creating a subclass:
namespace App\Http\Middleware;
use Spatie\Cors\Cors;
class CustomCors extends Cors
{
protected function handle($request, Closure $next)
{
// Custom logic (e.g., dynamic origin validation)
return parent::handle($request, $next);
}
}
Register it in Kernel.php.
Event Listeners:
Listen to cors.headers event to modify headers dynamically:
\Event::listen('cors.headers', function ($request, $response) {
if ($request->user()) {
$response->headers->set('X-Custom-Header', 'value');
}
});
Conditional Configuration:
Use environment-specific configs (e.g., .env variables) to toggle CORS:
'allowed_origins' => env('APP_ENV') === 'local'
? ['http://localhost:3000', 'http://127.0.0.1:8000']
: ['https://production.com'],
How can I help you explore Laravel packages today?