Laravel 12 Gates and Policies Explained: Best Practices & Examples

Author

Kritim Yantra

Mar 19, 2025

Laravel 12 Gates and Policies Explained: Best Practices & Examples

When building web applications, security is a top priority. One key aspect of security is authorization—deciding what users are allowed to do once they’re logged in. Laravel makes this task simple and elegant with two powerful tools: Gates and Policies. In this detailed blog post, we’ll explore how Gates and Policies work in Laravel 12, explain them in simple terms, and provide plenty of code examples to help you implement them in your projects. By the end, you’ll have a solid understanding of how to control user permissions like a pro!

Table of Contents

  1. What is Authorization and Why Does It Matter?
  2. What are Gates?
  3. How to Define and Use Gates
  4. What are Policies?
  5. Creating and Using Policies
  6. Gates vs. Policies: What’s the Difference?
  7. Advanced Tips for Gates and Policies
  8. Testing Your Authorization Rules
  9. Wrapping Up

What is Authorization and Why Does It Matter?

Before we dive into Gates and Policies, let’s clarify what authorization means. Imagine you’re running a blog site. You have users who can log in—that’s authentication, which checks who they are. But not every user should be able to delete posts; maybe only the post’s author or an admin should have that power. That’s where authorization comes in—it decides what a user can do.

In Laravel, Gates and Policies help you set these rules easily. Whether it’s restricting access to an admin dashboard or limiting who can edit a post, these tools keep your app secure and organized.


What are Gates?

Think of Gates as simple yes-or-no questions you can ask anywhere in your app. They’re like little guards that say, “Can this user do this action?” Gates are perfect for permissions that don’t depend on a specific object—for example, checking if someone can visit an admin page.

Gates are defined as small functions (closures) that return true or false. You set them up in one place and use them wherever needed.


How to Define and Use Gates

Step 1: Defining a Gate

Gates are usually defined in the AppServiceProvider (located in app/Providers/AppServiceProvider.php). For example:

<?php
use Illuminate\Support\Facades\Gate;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // Define a Gate to check if a user is an admin
        Gate::define('access-admin-panel', function ($user) {
            return $user->is_admin; // Assuming 'is_admin' is a column in your users table
        });
    }
}

In this example, the Gate named access-admin-panel checks if the logged-in user has the is_admin flag set to true.

Step 2: Using a Gate

Once the Gate is defined, you can use it anywhere in your app. For example, in a controller:

<?php
public function showAdminPanel()
{
    if (Gate::allows('access-admin-panel')) {
        return view('admin.panel'); // Show the admin panel
    } else {
        abort(403, 'Sorry, you’re not allowed here!');
    }
}

You can also use Gates in Blade templates with the @can directive:

@can('access-admin-panel')
    <a href="/admin">Go to Admin Panel</a>
@endcan

Gates can also accept additional parameters. For example, to check if a user can edit a specific post:

<?php
Gate::define('edit-post', function ($user, $post) {
    return $user->id === $post->user_id;
});

Then in a controller:

<?php
public function editPost($postId)
{
    $post = Post::findOrFail($postId);
    if (Gate::allows('edit-post', $post)) {
        return view('posts.edit', compact('post'));
    } else {
        abort(403);
    }
}

What are Policies?

Policies are classes that group authorization logic for a specific model. For example, a PostPolicy might contain methods to determine whether a user can update or delete a post.

Policies are ideal for actions like “view,” “create,” “update,” or “delete” on a specific model.


Creating and Using Policies

Step 1: Creating a Policy

Use Artisan to generate a policy for the Post model:

php artisan make:policy PostPolicy --model=Post

This creates app/Policies/PostPolicy.php, which might look like:

<?php
namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    public function update(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }

    public function delete(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }
}

Step 2: Registering the Policy

Laravel makes it easy to use policies. Policies help you decide if a user can do certain actions on a model (like a blog post or an order). There are two ways Laravel finds your policies:

  • Automatic Discovery: If you name your policy files correctly and place them in a folder named Policies (for example, app/Policies), Laravel will automatically match your models with their policies. For example, if you have a User model, the policy should be called UserPolicy.
  • Manual Registration: You can also tell Laravel exactly which policy goes with which model. This is done in the AppServiceProvider.

Here’s an example of manually registering a policy for a Post model:

<?php
use App\Models\Order;
use App\Policies\OrderPolicy;
use Illuminate\Support\Facades\Gate;
class AppServiceProvider extends ServiceProvider
{

    public function boot()
    {
        Gate::policy(Order::class, OrderPolicy::class);
    }
}

In this code, we tell Laravel that whenever it checks permissions for a Post, it should use the PostPolicy class. This keeps your authorization logic organized and easy to manage.

If you need custom logic to guess the policy name, you can use Gate::guessPolicyNamesUsing in your service provider’s boot method. However, sticking to the standard naming convention is usually enough for most applications.

Step 3: Using the Policy

In a controller, you can use the authorize method:

<?php
public function update(Request $request, Post $post)
{
    if (!$request->user()->can('update', $post)) {
       abort(403, 'Unauthorized');
    }
    $post->update($request->all());
    return redirect('/posts');
}

In Blade templates, you can use the @can directive:

@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}">Edit Post</a>
@endcan

Gates vs. Policies: What’s the Difference?

Both Gates and Policies are used for authorization, but they differ in scope:

  • Gates: Simple, standalone closures used for general rules (e.g., “Can this user access the admin panel?”).
  • Policies: Classes that encapsulate authorization logic for a specific model (e.g., post editing).

In practice, you might use Gates for general access rules and Policies for model-specific permissions.


Advanced Tips for Gates and Policies

Role-Based Gates

<?php
Gate::define('manage-users', function ($user) {
    return $user->hasRole('admin');
});

Use it like:

<?php
if (Gate::allows('manage-users')) {
    echo "Welcome, admin!";
}

Smarter Policies with the before Method

<?php
public function before($user, $ability)
{
    if ($user->is_admin) {
        return true; // Admins have full access
    }
}

This method runs before other policy methods and grants full access to admins.


Testing Your Authorization Rules

Testing a Gate

<?php
public function test_only_admins_can_access_admin_panel()
{
    // Create an admin user
    $admin = User::factory()->create(['is_admin' => true]);
    $this->actingAs($admin);
    $this->assertTrue(Gate::allows('access-admin-panel'));

    // Create a regular user
    $user = User::factory()->create(['is_admin' => false]);
    $this->actingAs($user);
    $this->assertFalse(Gate::allows('access-admin-panel'));
}

Testing a Policy

<?php
public function test_user_can_update_own_post()
{
    $user = User::factory()->create();
    $post = Post::factory()->create(['user_id' => $user->id]);

    $this->assertTrue($user->can('update', $post));

    $otherUser = User::factory()->create();
    $this->assertFalse($otherUser->can('update', $post));
}

Run your tests using php artisan test to ensure your authorization rules work as expected.


Wrapping Up

Laravel 12’s Gates and Policies are essential tools for managing user permissions. Gates offer a quick way to perform simple, general checks, while Policies provide a structured approach for model-specific authorization.

Remember:

  • Use Gates for standalone checks (e.g., “Is this user an admin?”)
  • Use Policies for detailed rules on specific models (e.g., “Can this user update this post?”)
  • Test your rules thoroughly to catch any mistakes early

With these tools, you can confidently control who does what in your Laravel application. Go ahead and start adding Gates and Policies to your project to keep your app safe and organized.

Happy coding!

Tags

Laravel Php

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Continue with Google

Related Posts

Understanding SOLID Design Principles in Laravel (For Beginners)
Kritim Yantra Kritim Yantra
Feb 24, 2025
Laravel 12 Roles and Permissions Setup: Complete Guide
Kritim Yantra Kritim Yantra
Feb 28, 2025
Laravel 12 & AdminLTE Integration: Setup Your Stunning Admin Dashboard
Kritim Yantra Kritim Yantra
Feb 28, 2025