Authentication proves who you are once, then a session cookie lets Laravel remember you on every request that follows.
🎟️It's like a music festival. At the gate you show your ID and ticket (email + password). They check it once and put a wristband on you (the session cookie). For the rest of the weekend, staff just glance at the wristband instead of asking for your ID again.
Almost every real app has a “Log in” button
Personal data
Dashboards, orders and drafts belong to one person. You need to know who is asking before you show them.
Security basics
Storing passwords safely and handling sessions correctly protects your users even if something leaks.
Demystify the magic
Starter kits write the login code for you. Knowing what happens underneath makes that code easy to read and change.
Two different questions
People mix these two words up all the time, so let's pin them down first.
- Authentication
- Who are you? Checking someone's identity, usually with an email and password. This is Module 07.
- Authorization
- What are you allowed to do? Checking whether a known user may edit this post. This is Module 08.
- Session
- A small bundle of data Laravel stores on the server (in a file, the database or Redis) for one visitor.
- Session cookie
- A random ID stored in the browser. It points to that visitor's session, so Laravel can find it again.
- Hash
- A one-way scramble of a password. You can check a guess against it, but you can't turn it back into the password.
As you saw in HTTP Basics, every request is independent. Without the session cookie, the server would have no idea that request #2 came from the same person who logged in on request #1.
Build a login by hand (once)
In real projects a starter kit writes this for you. Building it once by hand shows you exactly what that generated code does.
-
Never store plain passwords: hash them
Hashing turns
secret123into a long, random-looking string. Laravel uses bcrypt by default, which is deliberately slow so attackers can't guess millions of passwords per second.use Illuminate\Support\Facades\Hash; $hash = Hash::make('secret123'); // "$2y$12$Qm3k...a long string that changes every time" Hash::check('secret123', $hash); // true Hash::check('wrong-guess', $hash); // falseRun
Hash::maketwice on the same password and you get two different hashes. That's because of a random salt, andHash::checkstill handles it correctly. -
Let the model hash for you
The default
Usermodel already has ahashedcast. Any plain password you assign is hashed automatically before it's saved.protected function casts(): array { return [ 'email_verified_at' => 'datetime', 'password' => 'hashed', ]; }$user = User::create([ 'name' => 'Ada', 'email' => 'ada@example.com', 'password' => 'secret123', // stored as a bcrypt hash ]); -
Log in with
Auth::attemptAuth::attempt()finds the user by email, runsHash::checkon the password and, if it matches, stores the user's ID in the session. It returnstrueorfalse.<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class LoginController extends Controller { public function store(Request $request) { $credentials = $request->validate([ 'email' => ['required', 'email'], 'password' => ['required'], ]); if (Auth::attempt($credentials, $request->boolean('remember'))) { $request->session()->regenerate(); return redirect()->intended('/dashboard'); } return back()->withErrors([ 'email' => 'These credentials do not match our records.', ])->onlyInput('email'); } }redirect()->intended()sends the user back to the page they originally tried to visit, or to/dashboardif there wasn't one. -
Why
session()->regenerate()mattersRegenerating gives the visitor a brand-new session ID the moment they log in. This blocks session fixation, an attack where someone plants a known session ID in your browser and waits for you to log in with it.
⚠️ Always regenerate after loginSkipping this line doesn't break anything you can see, which is exactly why it's dangerous. Starter kits include it for you.
-
Wire up the routes and the form
The form is ordinary HTML with
@csrf. Theremembercheckbox sets a long-lived “remember me” cookie, so the user stays logged in after the browser closes.use App\Http\Controllers\LoginController; Route::view('/login', 'auth.login')->name('login')->middleware('guest'); Route::post('/login', [LoginController::class, 'store'])->middleware('guest');<form method="POST" action="/login"> @csrf <input type="email" name="email" value="{{ old('email') }}" required> <input type="password" name="password" required> <label><input type="checkbox" name="remember"> Remember me</label> @error('email') <p>{{ $message }}</p> @enderror <button>Log in</button> </form>You'll meet the
guestmiddleware and logging out properly in Guards & Protecting Routes.
Avoid this, do that
$user = User::where('email', $email)
->where('password', $password)
->first();
This only works if passwords are stored in plain text, which is a disaster waiting to happen.
if (Auth::attempt(['email' => $email, 'password' => $password])) {
$request->session()->regenerate();
}
Let Laravel look the user up and compare hashes safely.
'password' => md5($request->password),
MD5 and SHA1 are fast, so attackers can test billions of guesses. They are not password hashes.
'password' => Hash::make($request->password),
Use Hash::make (or the hashed cast), which is slow on purpose and salted automatically.
Say “These credentials do not match our records”, not “No account with that email”. Vague messages stop attackers from discovering which emails are registered. You'll learn more in Hashing & Encryption.
- Open
php artisan tinkerand runHash::make('hello')twice. Compare the two results. - Check one of those hashes with
Hash::check('hello', $hash)and with a wrong password. - Create a user in tinker with a plain password and look at the
passwordcolumn in the database. - Build the
LoginControllerabove and log in. Then open your browser dev tools and find thelaravel_sessioncookie. - Log in again and watch the cookie value change, thanks to
regenerate().
Key takeaways
- Authentication = who you are; authorization = what you may do.
- The password is checked once; after that, a session cookie identifies you.
- Store passwords with
Hash::make(or thehashedcast) and check them withHash::check. Auth::attempt($credentials)looks up the user, checks the hash and logs them in.- Always call
$request->session()->regenerate()right after a successful login.