benkle/auto-preflight-bundle
Installation
composer require benkle/auto-preflight-bundle
Register the Bundle
Add to config/app.php under providers:
Benkle\AutoPreflightBundle\BenkleAutoPreflightBundle::class,
And to config/app.php under aliases:
'AutoPreflight' => Benkle\AutoPreflightBundle\Facades\AutoPreflight::class,
Configure CORS
Add to config/cors.php (or create if missing):
'paths' => ['api/*'],
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
'allowed_origins' => ['*'],
'allowed_headers' => ['x-auth-token', 'content-type'],
First Use Case
Define a route with methods explicitly (e.g., POST):
Route::post('/api/resource', [ResourceController::class, 'store'])
->methods(['POST', 'OPTIONS']); // <-- Critical for preflight
Test with a curl preflight request:
curl -X OPTIONS -H "Origin: http://example.com" -H "Access-Control-Request-Method: POST" http://your-app.test/api/resource
Route Definition
Always include OPTIONS in the methods array for API routes:
Route::post('/api/data', [DataController::class, 'create'])
->methods(['POST', 'OPTIONS']);
OPTIONS requests if explicitly allowed.Dynamic Configuration Override default CORS settings per route using middleware:
Route::middleware(['cors:custom'])->post('/api/admin', [AdminController::class, 'store']);
Define custom in config/cors.php:
'custom' => [
'allowed_origins' => ['https://admin.example.com'],
'allowed_headers' => ['authorization', 'x-api-key'],
],
Facade Usage Manually trigger preflight responses (rarely needed):
use Benkle\AutoPreflightBundle\Facades\AutoPreflight;
public function customPreflight()
{
return AutoPreflight::respond([
'allow_origin' => 'https://trusted.com',
'allow_methods' => ['GET', 'POST'],
]);
}
Middleware Stack
Ensure AutoPreflightMiddleware runs before your API middleware:
$kernel->pushMiddlewareToGroup('api', \Benkle\AutoPreflightBundle\Http\Middleware\AutoPreflightMiddleware::class);
Missing OPTIONS Method
405 Method Not Allowed.OPTIONS to route methods() array.
Route::post('/endpoint')->methods(['POST', 'OPTIONS']);
Configuration Overrides
config/cors.php may conflict with Symfony’s native CORS.// config/bundles.php
Symfony\WebServerBundle\WarmupBundle::class => ['all' => true],
// Remove Symfony\Bundle\FrameworkBundle\HttpCache\HttpCacheBundle if present
Header Injection Quirks
allow_headers is treated as a comma-separated string, not an array.
# config/cors.php
allowed_headers: 'content-type,x-auth-token,X-Custom-Header'
Caching Headers
Vary: Origin to preflight responses:
// In AutoPreflightMiddleware
$response->headers->set('Vary', 'Origin');
Log Preflight Requests
Add to AutoPreflightMiddleware:
\Log::debug('Preflight request', [
'origin' => $request->headers->get('Origin'),
'method' => $request->headers->get('Access-Control-Request-Method'),
]);
Validate Headers
Use dd() to inspect headers in a controller:
public function __invoke(Request $request)
{
dd($request->headers->all());
}
Test with Postman
Method: OPTIONS.Origin: http://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: x-auth-token
Custom Response Logic Override the middleware class:
// app/Http/Middleware/CustomPreflightMiddleware.php
namespace App\Http\Middleware;
use Benkle\AutoPreflightBundle\Http\Middleware\AutoPreflightMiddleware as BaseMiddleware;
class CustomPreflightMiddleware extends BaseMiddleware
{
protected function getAllowedMethods(): array
{
return ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'];
}
}
Register it in AppServiceProvider:
public function boot()
{
$this->app->bind(
\Benkle\AutoPreflightBundle\Http\Middleware\AutoPreflightMiddleware::class,
\App\Http\Middleware\CustomPreflightMiddleware::class
);
}
Event Listeners Listen for preflight events (if the bundle emits them):
// config/events.php
'Benkle\AutoPreflightBundle\Events\PreflightHandled' => [
\App\Listeners\LogPreflight::class,
],
How can I help you explore Laravel packages today?