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 kit | What it gives you |
|---|---|
| Laravel Breeze | The current, lightweight starting point — simple Blade views and routes for login, registration, and password reset, minimal and easy to read through and customize |
| Laravel Fortify | A 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 Jetstream | A more feature-rich kit built on Fortify, adding things like team management, two-factor authentication, and API token support out of the box |
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.