Skip to content

Conversation

emargareten
Copy link
Contributor

This PR adds a new #[Authorize] attribute that allows you to authorize controller actions instead of manually calling authorization inside the method.

Examples:

// simple authorization without parameters
#[Authorize('create-post')] 
public function store()
{
    // replaces Gate::authorize('create-post')
}

// with explicit model parameters
#[Authorize('update-post', 'post')]
public function updatePost(Post $post)
{
    // replaces Gate::authorize('update-post', $post)
}

// auto-resolve parameters from method signature
#[Authorize('update-post')]
public function updatePost(Post $post)
{
    // Automatically passes $post to gate based on type hint
}

@Copilot Copilot AI review requested due to automatic review settings August 26, 2025 21:10
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a new #[Authorize] attribute for controller actions that provides declarative authorization without requiring manual Gate::authorize() calls inside methods.

  • Adds #[Authorize] PHP attribute for method-level authorization
  • Implements automatic model parameter resolution from method signatures
  • Integrates authorization checks into the ControllerDispatcher workflow

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/Illuminate/Auth/Attributes/Authorize.php Defines the new Authorize attribute class with ability and model parameters
src/Illuminate/Routing/ControllerDispatcher.php Implements authorization handling logic in the dispatch method
tests/Auth/AuthorizeAttributeTest.php Unit tests for the Authorize attribute instantiation
tests/Routing/ControllerDispatcherAuthorizeAttributeTest.php Tests for basic authorization scenarios with the dispatcher
tests/Routing/AuthorizeAttributePolicyTest.php Tests for policy-based authorization using the attribute
tests/Routing/AuthorizeAttributeIntegrationTest.php Integration tests covering edge cases and complex scenarios

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Updated the Authorize attribute to remove IS_REPEATABLE option.
@browner12
Copy link
Contributor

Ok, I'll admit I was very anti-Attribute when they first started popping up. I was probably extra hesitant because of how poorly Annotations went, and at first it felt like the same hype that was pushed back then. However, I'm coming around to them, and definitely see their use in certain cases.

One great example of a good use of Attributes is the CollectedBy attribute. Previously in order to customize Eloquent Collections we had to override the newCollection() method. At first, this was fine, because the only thing the parent model did was return an Eloquent\Collection. As the base method started getting more complicated it started introduced issues. Specifically, when automatic eager loading was added (#55443) this was broken when people overrode the newCollection method, unless they updated their override method as well. Attributes were a great solution here because there's only 1 piece of information in there that NEEDS to be customized, and Attributes allowed us to hyper-focus on that custom Collection class name, without worrying about all the other crap in the method.

Here, however, we're taking an incredibly simple 1 line method call (Gate::authorize()) and replacing it with an equally simple 1 line Attribute. I am struggling to understand why we would do this. Does it make something easier? Does it open up new functionality that didn't exist before? Is it better, or is it just different? I would argue it's even a little less readable. Previously we had a $post variable called in the method body that was passed in from a $post parameter in the method signature. Pretty straightforward, and IDEs could easily make the connection. Now we're replacing it with some unnecessary hidden logic? I don't get it.

We've also now got the additional burden of maintaining the Attribute. Some could argue it's not that big a deal, but it is a non-insignificant amount of code. It's not going to kill us, but it definitely contributes to death by 1000 cuts.

sorry for the /rant

TLDR: Attribute seems completely unnecessary here and not worth the additional code.

@emargareten
Copy link
Contributor Author

@browner12
I think that an attribute makes sense when it’s not really part of the “main logic” of the class/method but more of a concern that sits around it. For me, Gate::authorize() feels more like “metadata” about the action -it says what needs to be true before this runs, not what the action itself does, that’s why I thought an attribute might be a nice declarative way to show that intent.

@cfeldbrand
Copy link

I actually really like the idea of an attribute for authorization.

I noticed @browner12 mentioned you were very anti-Attribute at first, and I think maybe that’s part of where the pushback is coming from now.

As @emargareten pointed out, Attributes in PHP aren’t just for swapping out a 1-liner or for “hiding” logic. They’re actually about attaching structured, machine-readable metadata to code — a way of expressing rules, configuration, or intent about a method or class, rather than putting everything into the main logic, meaning that if something is core to the flow of the method, it should stay there, but if it’s a rule or constraint — something external that should be easily discoverable, then an Attribute is a natural place for it.

There have also been some recent discussions on twitter and in the community about where authorization logic should typically go, whether inside controller methods, in the routes file (as middleware), or in form request classes. Some people feel it’s not really the controller’s job to handle authorization; others point out that for certain methods like index or create, there isn’t always a dedicated form request, and routes/middleware don’t always cover everything clearly. From that perspective, having authorization declared as an Attribute looks like a very consistent, clean, and discoverable way to express access rules directly alongside the action, it centralizes the authorization intent without blending it into business logic, and without scattering it in multiple unrelated places.

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.

3 participants