Gates — simple closures for authorization logic
Beginner5 min read·lv-17-001
interview
Concept
Gates are the simplest authorization mechanism in Laravel — plain closures that receive a user and optionally extra arguments, and return true (allowed) or false (denied).
When to use Gates vs Policies:
- Gates: Authorization logic NOT tied to a specific Eloquent model. "Is this user an admin?", "Can this user access the beta feature?".
- Policies: Authorization logic scoped to a specific model. "Can this user update THIS post?". (Covered in lv-17-002.)
Defining gates: Gate::define() in AppServiceProvider::boot() (or a dedicated AuthServiceProvider).
php
Gate::define('view-admin', fn(User $user) => $user->isAdmin());
Gate::define('edit-post', fn(User $user, Post $post) => $user->id === $post->user_id);Checking gates:
Gate::allows('view-admin'): Returns bool.Gate::denies('view-admin'): Inverse.Gate::check(['edit-post', 'delete-post'], $post): All must pass.Gate::any(['edit-post', 'delete-post'], $post): Any must pass.Gate::authorize('view-admin'): ThrowsAuthorizationException(→ 403) if denied.$request->user()->can('edit-post', $post): Via theAuthorizabletrait.
Blade directives: @can('edit-post', $post), @cannot, @canany.
Unauthenticated users: If no user is authenticated, Gate closures receive null. Design accordingly.
Code Example
php
<?php
// AppServiceProvider::boot() — define gates
use Illuminate\Support\Facades\Gate;
Gate::define('view-admin-dashboard', function(User $user): bool {
return $user->role === 'admin';
});
Gate::define('manage-feature-flags', function(User $user): bool {
return in_array($user->role, ['admin', 'super-admin']);
});
Gate::define('edit-post', function(User $user, Post $post): bool {
return $user->id === $post->user_id || $user->role === 'admin';
});
Gate::define('delete-post', function(User $user, Post $post): bool {
return $user->id === $post->user_id && !$post->is_published;
});
// Using gates in controllers
public function adminPanel()
{
Gate::authorize('view-admin-dashboard'); // throws 403 if denied
return view('admin.dashboard');
}
public function edit(Post $post)
{
if (Gate::denies('edit-post', $post)) {
abort(403, 'You cannot edit this post.');
}
return view('posts.edit', compact('post'));
}
// Using gate on the user model (Authorizable trait)
if ($request->user()->can('edit-post', $post)) {
// show edit button
}
if ($request->user()->cannot('delete-post', $post)) {
abort(403);
}
// Multiple gates at once
if (Gate::any(['edit-post', 'delete-post'], $post)) {
// user can do at least one
}
if (Gate::check(['edit-post', 'delete-post'], $post)) {
// user can do BOTH
}
// Blade
// @can('edit-post', $post)
// <a href="{{ route('posts.edit', $post) }}">Edit</a>
// @endcan
// @cannot('edit-post', $post)
// <span>Read only</span>
// @endcannot