Advanced LaravelPro· 40 min read

Authorization: Gates & Policies

Authentication asks “who are you?” — authorization asks “are you allowed to do this?”. Control exactly what each user can do.

What you will learn

  • Tell authentication and authorization apart
  • Write a Gate for a simple check
  • Write a Policy to protect a model’s actions

Two different questions

It is easy to mix these up, so let us define them clearly:

  • Authentication = "who are you?" — logging in proves your identity. (You did this with Breeze.)
  • Authorization = "are you allowed?" — once we know who you are, may you edit *this* post, or delete *that* product?

A logged-in user should usually only edit their own posts, not everyone’s. Laravel gives you two tools for these rules: Gates (for simple, one-off checks) and Policies (for organising all the rules about one model).

Gates — a simple yes/no rule

A Gate is a small closure that returns true or false. Define gates in a service provider’s boot() method. Here is one that allows only admins:

Define a gate: only admins may access the admin area
// in a service provider's boot() method
use Illuminate\Support\Facades\Gate;

Gate::define('access-admin', function ($user) {
    return $user->is_admin === true;
});

The gate is named access-admin. Laravel passes the current $user in automatically; the closure returns true only if that user is an admin. Now you check the gate anywhere:

Check the gate in PHP and in Blade
// in a controller
if (Gate::allows('access-admin')) {
    // show the admin dashboard
}

// in Blade
@can('access-admin')
  <a href="/admin">Admin Panel</a>
@endcan

Gate::allows('access-admin') returns true or false for the logged-in user. In Blade, @can('access-admin') ... @endcan shows its contents only if the user passes — so non-admins never even see the admin link.

Policies — all the rules for one model

When a model has several actions to guard (view, update, delete), a Policy keeps them together in one class. Generate one tied to a model:

Generate a policy for the Post model
php artisan make:policy PostPolicy --model=Post

Inside the policy, each method is one action. They receive the logged-in $user and the $post in question, and return true if it is allowed. Here, a user may update or delete a post only if they own it:

A user may edit/delete only their own posts
// app/Policies/PostPolicy.php
public function update(User $user, Post $post): bool
{
    return $user->id === $post->user_id;
}

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

The rule $user->id === $post->user_id reads as "is the logged-in user the same person who owns this post?". If yes, the action is allowed; if no, it is blocked. You wrote the ownership rule once, in the obvious place.

You enforce a policy in the controller with $this->authorize():

Enforce the policy before updating
// in the controller
public function update(Request $request, Post $post)
{
    $this->authorize('update', $post);   // blocks with 403 if not allowed
    // ...update the post...
}

$this->authorize('update', $post) runs the policy’s update method for the current user and this post. If it returns false, Laravel immediately stops with a 403 Forbidden response (403 is the standard code for "you are logged in, but not allowed"). If it returns true, your update code runs.

Note: Output: Owner clicks "Edit" on their post → authorize passes, the post updates. A different user tries the same URL → authorize fails → Laravel returns a 403 Forbidden page. The ownership rule is enforced in one place.

The decision flow for any guarded action:

  1. The user is authenticated — we know who they are.
  2. They try an action (e.g. update post 7).
  3. The controller calls $this->authorize('update', $post) (or a @can check in Blade).
  4. Laravel runs the matching Gate/Policy method, passing the user and the model.
  5. Return true → the action proceeds; return false → Laravel blocks it with a 403.

Tip: Rule of thumb: use a Gate for a quick app-wide check ("is admin?"), and a Policy when you have several rules about one model ("can view/update/delete this post"). Both power the same @can and authorize helpers.

Q. What does authorization (gates/policies) decide that authentication does not?

Answer: Authentication proves identity (login). Authorization decides if that identity may do a specific thing — e.g. edit only their own post — via Gates and Policies.

✍️ Practice

  1. Define a Gate and guard a link with @can in Blade.
  2. Generate a Policy so users can edit only their own records, and enforce it with $this->authorize().

🏠 Homework

  1. Add a PostPolicy so only the author can edit or delete a post, and hide the edit/delete buttons from everyone else with @can.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →