Laravel Policies Explained: Authorization Step by Step

February 10, 2025 · 4 min read

2026 UPDATE - LARAVEL 13
We’re excited to announce that we have updated all of our blog post examples to reflect the new Laravel 13 version! Our previous examples were based on Laravel 10, but with the release of Laravel 13, we wanted to ensure that our readers have access to the most up-to-date information and examples.
What are Laravel Policies?
Policies in Laravel are classes that hold the authorization logic for a specific model. Think of them as the gatekeepers who decide if a user can do something with a resource. By using policies, you keep your controllers clean and focused on handling requests and responses.
Why Use Policies in Laravel?
Using policies in Laravel has several benefits:
Separation of Concerns: Policies help you keep your business logic separate from your authorization rules. This makes your code more organized, easier to test, and simpler to maintain.
Reusability: By placing your authorization rules in one place, can use them across multiple controllers and methods without repeating code.
Consistency: Policies ensure that your rules are applied the same way throughout your app, reducing the chance of security issues.
A Policy for our Blog example
Creating a Policy in Laravel
Creating a policy in Laravel is easy. You can generate a policy using the Artisan command:
php artisan make:policy PostPolicy
This command will create a new policy class in the app/Policies directory. If the directory doesn’t exist, Laravel will create it for you. The generated policy will be empty, but you can use the --model option to include predefined methods for common actions like viewing, creating, updating, and deleting:
php artisan make:policy PostPolicy --model=Post
This will create a policy class with methods for actions users might perform on the Post model. You can use this class to continue with our blog example.
Registering a Policy
In Laravel 13, if you follow the standard naming conventions, policies will be automatically discovered and registered by Laravel. We already have a Post model, so a corresponding PostPolicy class will be automatically linked.
However, if you prefer to manually register policies, you can do so in the boot method of your AppServiceProvider.
Modifying the Policy class
Here’s an example of a simple policy method that determines if a user can update a post:
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
}In this example, the update method checks if the user’s ID matches the user_id on the post. If it does, the method returns true, allowing the user to update the post.
Using a Policy
Once your policies are created and registered, you can use them to control actions in your controllers or routes. For example, to check if a user can update a post, you can use the authorize method in your controller:
namespace App\Http\Controllers;
use App\Models\Post;
use App\Models\Tag;
use Illuminate\Http\Request;
class PostController extends Controller
{
// Update the specified blog post
public function update(Request $request, Post $post)
{
if ($request->user()->cannot('update', $post)) {
abort(403);
}
$validatedData = $request->validate([
'title' => 'required|max:255',
'content' => 'required',
// other validation rules...
]);
$tags = $request->validate([
'tags' => 'required',
]);
$post->update($validatedData);
// we modify the tags of the post by using the sync() method
$post->tags()->sync($tags);
return redirect()->route('posts.show', $post);
}
}This will check the update method in the PostPolicy class to determine if the user is allowed to update the post.
There are a couple of ways to do this. Let’s see them together:
Using a regular check through the request user.
// Update the specified blog post
public function update(Request $request, Post $post)
{
if ($request->user()->cannot('update', $post)) {
abort(403);
}
$validatedData = $request->validate([
'title' => 'required|max:255',
'content' => 'required',
// other validation rules...
]);
$tags = $request->validate([
'tags' => 'required',
]);
$post->update($validatedData);
// we modify the tags of the post by using the sync() method
$post->tags()->sync($tags);
return redirect()->route('posts.show', $post);
}Using a Gate.
use Illuminate\Support\Facades\Gate;
// Update the specified blog post
public function update(Request $request, Post $post)
{
Gate::authorize('update', $post);
$validatedData = $request->validate([
'title' => 'required|max:255',
'content' => 'required',
// other validation rules...
]);
$tags = $request->validate([
'tags' => 'required',
]);
$post->update($validatedData);
// we modify the tags of the post by using the sync() method
$post->tags()->sync($tags);
return redirect()->route('posts.show', $post);
}Using a middleware for our edit route to prevent access. However, a couple of lessons before we used a resource controller for posts, so we will need to slightly modify that. As you can see in the last line we can simply use
can('edit', 'post');to use our policy.
// We currently have this on our web.php file
Route::resource('posts', PostController::class);
// Let's remove the edit method from that
Route::resource('posts', PostController::class)->except('edit');
// we create a new route for the edit method
Route::get('/posts/{post}/edit', [PostController::class, 'edit'])
->name('post.edit')
->can('edit', 'post');Conclusion
In Laravel 13, policies are essential for managing authorization. They offer a clean way to separate and centralize your authorization logic, keeping your code modular, reusable, and consistent. With automatic discovery and registration in Laravel 13, using policies is now easier than ever. By mastering policies, you can ensure your application remains secure and maintainable as it grows.
Upcoming Articles in the Series
Laravel for Beginners: Roles and Permissions with Spatie package
Laravel for Beginners: Differences of using Policies vs Roles and Permissions
Laravel for Beginners: Using Laravel Spark with Stripe and Paddle
This article is part of our series Laravel for Beginners: A Step-by-Step Guide to Learn the Concepts.
Bring Your Ideas to Life 🚀
If you need help with a Laravel project let’s get in touch.
Lucky Media is proud to be recognized as a leading Laravel Development Agency
Technologies

Stay up-to-date
Be updated with all news, products and tips we share!

