Authentication

Almost every real application needs some way for users to register, log in, and log out. Laravel doesn't force you to build that from scratch — it ships several official starter kits that scaffold registration, login, password reset, and email verification for you, plus a small, consistent API (the Auth facade) for checking who's logged in from anywhere in your code, regardless of which starter kit you chose.

Starter Kits: Breeze, Fortify, and Jetstream

You are never required to use one of these — you could write your own login form and controller by hand — but for the vast majority of applications, a starter kit saves days of repetitive, easy-to-get-wrong work (password hashing, CSRF protection, rate-limiting login attempts, and so on).

Starter kitWhat it gives you
Laravel BreezeThe current, lightweight starting point — simple Blade views and routes for login, registration, and password reset, minimal and easy to read through and customize
Laravel FortifyA headless, backend-only implementation of the same features — no views included at all, ideal when your frontend is fully custom or built with something like Vue or React
Laravel JetstreamA more feature-rich kit built on Fortify, adding things like team management, two-factor authentication, and API token support out of the box
Note: All three ultimately rely on the same underlying authentication system described below — they only differ in how much scaffolding and UI they hand you up front.

Checking Auth State: The Auth Facade

Regardless of which starter kit (or hand-rolled solution) you use, the Auth facade is the standard way to check authentication state anywhere in your application — a controller, a middleware, a Blade view, anywhere.

Auth::check();   // true if a user is currently logged in
Auth::user();    // the full logged-in User model, or null if a guest
Auth::id();      // just the logged-in user's primary key, or null

The auth() Helper: A Shorthand

The global auth() helper function is exact shorthand for the Auth facade — both refer to the same underlying authentication manager, so use whichever reads more naturally in context.

// These two lines do exactly the same thing
$user = Auth::user();
$user = auth()->user();

Protecting Routes with Middleware

Checking Auth::check() manually inside every controller method that requires a logged in user would be repetitive and easy to forget. Instead, Laravel's bundled auth middleware handles it declaratively at the route level — see Middleware for the full picture of how middleware wraps a request.

Route::get('/dashboard', [DashboardController::class, 'index'])->middleware('auth');

Any request to /dashboard from a guest (not logged in) is automatically redirected to the login page — the controller method never even runs.

Logging a User In and Out Manually

Starter kits generate the login controller logic for you, but it's worth knowing what's actually happening underneath. Auth::attempt() takes an array of credentials, verifies the password against the hashed value stored in the database, and — if it matches — logs the user in for the current session:

if (Auth::attempt(['email' => $email, 'password' => $password])) {
    return redirect()->intended('/dashboard');
}

return back()->withErrors([
    'email' => 'These credentials do not match our records.',
]);

Logging out is a single call, which invalidates the user's session:

Auth::logout();

Blade Directives: @auth and @guest

Blade — covered in Blade Templating Basics — provides two dedicated directives for conditionally rendering content based on login state, so you don't have to write out @if(Auth::check()) everywhere.

<ul class="nav navbar-nav">
  @auth
    <li>Welcome, {{ auth()->user()->name }}</li>
    <li><a href="{{ route('logout') }}">Logout</a></li>
  @endauth
  @guest
    <li><a href="{{ route('login') }}">Login</a></li>
  @endguest
</ul>

When a user is logged in, @auth's content renders and @guest's is skipped; for a visitor who hasn't logged in, it's the reverse. This is the standard pattern behind the "Login" / "Logout" toggle you see in almost every navigation bar.

Accessing the Logged-In User in a View

Inside any Blade view, the same auth()->user() call (or Auth::user()) gives you the full User model, so you can access any of its attributes directly:

{{ auth()->user()->name }}
{{ Auth::user()->email }}

Passwords Are Always Hashed

One thing you should never do — and Laravel's built-in auth scaffolding never lets you accidentally do — is store a plaintext password. Every starter kit hashes passwords automatically using bcrypt (or Argon2) before they're ever written to the database, and Auth::attempt() compares the submitted password against that hash rather than any stored plaintext value. Even if your database were somehow exposed, actual passwords are never recoverable from what's stored.

Where this leads: Knowing WHO is logged in is only half the picture — the next lesson covers what a logged-in user is actually ALLOWED to do, in Authorization: Gates & Policies.