Skip to content

[13.x] Add per-route CORS configuration support#59305

Open
WendellAdriel wants to merge 2 commits into13.xfrom
feat/per-route-cors
Open

[13.x] Add per-route CORS configuration support#59305
WendellAdriel wants to merge 2 commits into13.xfrom
feat/per-route-cors

Conversation

@WendellAdriel
Copy link
Copy Markdown
Member

@WendellAdriel WendellAdriel commented Mar 20, 2026

Overview

This PR adds route-specific CORS handling while moving that behavior into dedicated route middleware, so per-route policies can use the already-resolved route instead of matching requests twice.

Approach

  • Keep the existing global CORS configuration as the fallback for configured paths.
  • Apply route-specific CORS through middleware in the web and api groups so route metadata and controller attributes are resolved from the active route.
  • Carry the intended route information through preflight handling so OPTIONS requests use the same route-specific policy as the underlying endpoint.

Examples

Route-level configuration:

use Illuminate\Support\Facades\Route;

Route::get('/profile', fn () => ['name' => 'Taylor'])
    ->cors([
        'origins' => ['https://app.example.com'],
        'methods' => ['GET'],
        'headers' => ['Content-Type', 'X-Requested-With'],
    ]);

Class-level attribute:

use Illuminate\Routing\Attributes\Cors;

#[Cors(origins: ['https://admin.example.com'], methods: ['GET', 'POST'])]
class AdminProfileController
{
    public function __invoke()
    {
        return ['name' => 'Taylor'];
    }
}

Class method-level attribute:

use Illuminate\Routing\Attributes\Cors;

class ReportController
{
    #[Cors(origins: ['https://reports.example.com'], methods: ['GET'])]
    public function show()
    {
        return ['status' => 'ok'];
    }
}

Allow CORS options to be defined at the route level via a fluent
cors() method, route group option, or #[Cors] attribute, giving
fine-grained control over cross-origin policies without modifying
the global CORS configuration.
@WendellAdriel WendellAdriel marked this pull request as ready for review March 20, 2026 19:21
@taylorotwell
Copy link
Copy Markdown
Member

Hmm, one change I might make to this is to potentially make a new middleware in the web and api groups that is specifically for route CORS. That way you don't have to do the route matching twice and the route will already be available on $request->route().

@taylorotwell taylorotwell marked this pull request as draft March 21, 2026 11:36
@WendellAdriel WendellAdriel marked this pull request as ready for review March 22, 2026 16:14
@WendellAdriel
Copy link
Copy Markdown
Member Author

Just pushed some changes with a different approach @taylorotwell
Check if that's ok or if you want me to work in a diff one, thanks for the review! 💪

@WendellAdriel WendellAdriel changed the title Add per-route CORS configuration support [13.x] Add per-route CORS configuration support Mar 25, 2026
@martinbean
Copy link
Copy Markdown
Contributor

martinbean commented Mar 30, 2026

I like the idea of this, but in my experience CORS has always been far more complicated than, “allow requests for this one hostname only”. This approach even falls down when you have multiple environments for a single application with their own unique hostnames, so hard-coded hostname (or array of hostnames) in an attribute is not going to cut it.

/**
* Get the CORS options as an array, excluding null values.
*
* @return array
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can narrow this down:

Suggested change
* @return array
* @return array<string, array<string>|int|bool>

or

Suggested change
* @return array
* @return array{
* origins?: array<string>,
* methods?: array<string>,
* headers?: array<string>,
* exposed_headers?: array<string>,
* max_age?: int,
* credentials?: bool,
* }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants