Authentication answers 'who are you?'; authorization answers 'are you allowed to do this?'. Laravel offers two mechanisms: Gates (simple closures) and Policies (organized per-model classes).
Gates — good for quick, app-wide actions not tied to a specific model:
// In AppServiceProvider::boot()
Gate::define('access-admin-panel', function (User $user) {
return $user->role === 'admin';
});
// Usage
if (Gate::allows('access-admin-panel')) { ... }
Policies — the recommended approach for model-specific authorization:
php artisan make:policy PostPolicy --model=Post
class PostPolicy
{
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 || $user->isAdmin();
}
}
Usage in controllers, views, and Form Requests:
$this->authorize('update', $post); // Throws 403 automatically if denied
@can('update', $post) <a>Edit</a> @endcan // Blade
$user->can('delete', $post) // Anywhere
Policies are auto-discovered by naming convention in modern Laravel versions, so there's usually no need to manually register them.