Skip to main content
Guest User Gates

Guest User Gates

Most authorization assumes a signed-in user. Some applications also need rules for visitors who are not authenticated: preview a public draft, access a shared link, or submit a limited action. Guest-aware gates make those rules explicit instead of scattering null checks through controllers.

What a guest is

A guest is a request with no authenticated user. Laravel's authorization layer receives null when no user is present. Policies and gates may accept a nullable user when the ability makes sense for visitors.

A guest-aware gate

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    Gate::define('preview-post', function (?User $user, Post $post) {
        if ($post->isPublished()) {
            return true;
        }

        return $user !== null && $user->can('update', $post);
    });
}

The ?User type allows the gate to run for both guests and signed-in users. Without the nullable marker, Laravel would deny guests before the closure runs.

Using the gate

public function show(Post $post)
{
    Gate::authorize('preview-post', $post);

    return view('posts.show', compact('post'));
}

In Blade, @can works the same way and returns false for a guest when the gate requires a user.

@can('preview-post', $post)
    <a>Read preview</a>
@endcan

Optional authentication

The auth middleware rejects guests. For pages that behave differently when a user is present, use an optional guard check instead.

public function index(Request $request)
{
    $user = $request->user(); // null for guests

    $posts = $user
        ? Post::where('team_id', $user->team_id)
        : Post::published();

    return view('posts.index', compact('posts'));
}

Do not apply auth middleware and then branch on $request->user() for a guest branch; the middleware has already redirected. Either protect the route fully or leave it public with explicit guest logic.

Guest rate limits

Public actions still need abuse protection. Limit guest submissions by IP and require authentication for anything expensive.

RateLimiter::for('guest-actions', function (Request $request) {
    return $request->user()
        ? Limit::none()
        : Limit::perMinute(5)->by($request->ip());
});

Design guidance

  • Prefer public routes for genuinely public content; do not force guests through a login wall.
  • Use gates with nullable users only when the rule is part of the domain, not as a workaround for broken middleware.
  • Record who performed a guest action through a signed token or verified email, not a hidden user ID field.
  • Review guest abilities during security testing, especially anything that creates or reveals data.