In one sentence

The auth middleware locks a route so only logged-in users get through, and a guard is the rulebook that decides how Laravel recognises those users.

πŸ’‚Picture a club. The bouncer at the door is the auth middleware: no wristband, no entry. The guard is the club's policy on what counts as a valid wristband. For the main room that's a paper wristband (a session), and for the VIP API lounge it's a scanned QR code (a token).

Why it matters

Logging in is only useful if pages check for it

🚧

Private pages stay private

One word, auth, keeps strangers out of dashboards, settings and drafts.

πŸ™‹

Personalise everything

Once you can read the current user, you can show their name, their posts and their settings.

🧭

Smooth redirects

Guests get sent to login, and logged-in users skip the login page. Both are configured in one place.

The big picture

What the auth middleware does

🌐RequestGET /dashboard + cookie
πŸ’‚auth middlewareasks the guard: who is this?
βœ…Known usercontroller runs
↩️Guestredirect to /login
Middleware runs before your controller (see Middleware). If there's no logged-in user, the controller never runs at all.
MiddlewareLets throughOtherwiseTypical routes
authLogged-in usersRedirects to /loginDashboard, settings, β€œnew post”
guestVisitors who are not logged inRedirects to the home/dashboardLogin, register, forgot password
Step by step

Lock pages down and use the current user

  1. Protect routes with auth (and guest)

    Add the middleware to a single route, or wrap a whole group so you can't forget one.

    
              use App\Http\Controllers\PostController;
    
              Route::get('/dashboard', fn () => view('dashboard'))
                  ->middleware('auth')->name('dashboard');
    
              Route::view('/login', 'auth.login')->middleware('guest')->name('login');
    
              Route::middleware('auth')->group(function () {
                  Route::resource('posts', PostController::class)->except(['index', 'show']);
              });
            

    Here anyone can read posts, but only logged-in users can create, edit or delete them.

  2. Read the logged-in user

    There are three common ways to get the current user. They all return the same User model, or null for a guest.

    
              use Illuminate\Http\Request;
              use Illuminate\Support\Facades\Auth;
    
              public function index(Request $request)
              {
                  $user = $request->user();   // from the request (great in controllers)
                  $user = Auth::user();        // facade
                  $user = auth()->user();      // helper
    
                  $id = Auth::id();             // just the ID
                  $loggedIn = Auth::check();    // true / false
    
                  $posts = $request->user()->posts()->latest()->get();
    
                  return view('dashboard', compact('posts'));
              }
            

    The posts() relationship comes from Relationships. Using it means each user only ever sees their own posts.

  3. Show and hide things in Blade

    Use @auth and @guest to switch parts of a layout. Inside a view, auth()->user() works too.

    
              <nav>
                  @auth
                      Hi, {{ auth()->user()->name }}!
                      <a href="{{ route('dashboard') }}">Dashboard</a>
                      <form method="POST" action="{{ route('logout') }}">
                          @csrf
                          <button>Log out</button>
                      </form>
                  @endauth
    
                  @guest
                      <a href="{{ route('login') }}">Log in</a>
                      <a href="{{ route('register') }}">Register</a>
                  @endguest
              </nav>
            
    ⚠️ Hiding a link isn't protection

    @auth only changes what's displayed. Anyone can still type the URL directly, so the route itself must use the auth middleware.

  4. Log out properly

    Logging out takes three lines: forget the user, destroy the session and issue a new CSRF token. Always use a POST form, never a plain link. Otherwise another site could log your users out with a simple <img> tag.

    
              use Illuminate\Http\Request;
              use Illuminate\Support\Facades\Auth;
    
              Route::post('/logout', function (Request $request) {
                  Auth::logout();
                  $request->session()->invalidate();
                  $request->session()->regenerateToken();
    
                  return redirect('/');
              })->middleware('auth')->name('logout');
            
  5. Meet guards in config/auth.php

    A guard defines how users are recognised on each request. A provider defines where they're loaded from. The default web guard uses the session plus the users table.

    
              'defaults' => [
                  'guard' => env('AUTH_GUARD', 'web'),
                  'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
              ],
    
              'guards' => [
                  'web' => [
                      'driver' => 'session',     // remember users with a session cookie
                      'provider' => 'users',
                  ],
              ],
    
              'providers' => [
                  'users' => [
                      'driver' => 'eloquent',
                      'model' => env('AUTH_MODEL', App\Models\User::class),
                  ],
              ],
            

    Most apps only ever use web. APIs add a token-based guard, like auth:sanctum (see Sanctum). You can pick a guard explicitly with Auth::guard('web')->user() or ->middleware('auth:sanctum').

  6. Change where people get redirected

    In Laravel 11+, you configure redirects in bootstrap/app.php. There's no Http/Kernel.php any more.

    
              ->withMiddleware(function (Middleware $middleware) {
                  // where `auth` sends guests, and where `guest` sends logged-in users
                  $middleware->redirectGuestsTo('/login');
                  $middleware->redirectUsersTo('/dashboard');
              })
            

    By default, guests are sent to the route named login. If your login page has a different name, this is the place to fix it.

Common mistakes

Avoid this, do that

❌ Avoid

          public function index()
          {
              if (! Auth::check()) {
                  return redirect('/login');
              }
              // ...
          }
        

Repeating the check in every method is easy to forget, and one missed method means a leaked page.

βœ… Do

          Route::middleware('auth')->group(function () {
              Route::get('/dashboard', ...);
              Route::get('/settings', ...);
          });
        

Declare protection once, at the route level, where it's visible in route:list.

❌ Avoid

          <a href="/logout">Log out</a>
        

A GET logout can be triggered by any page on the internet, and it skips CSRF protection.

βœ… Do

          <form method="POST" action="{{ route('logout') }}">
              @csrf <button>Log out</button>
          </form>
        

A POST form with @csrf can only be submitted from your own site.

πŸ’‘ Pro tip: null-safe user access

On pages guests can see, auth()->user() may be null. Use the null-safe operator: auth()->user()?->name.

πŸ‹οΈ Try it yourself
  1. Create a /secret route protected by auth, and visit it while logged out. Where do you end up?
  2. Visit /login while logged in and check that the guest middleware redirects you.
  3. Add a nav bar that shows the user's name with @auth and login/register links with @guest.
  4. Change redirectUsersTo in bootstrap/app.php to /posts and test it.
  5. Open config/auth.php and find the web guard and the users provider.
Recap

Key takeaways

Check yourself

Mini quiz