Semua yang kita bangun di chapter-chapter sebelumnya — status login, intended URL, flash message — bertumpu pada satu fondasi: session. Memahami cara Laravel menyimpan dan memutarnya membuat kita bisa menjawab pertanyaan praktis: bagaimana melihat perangkat mana saja yang sedang login, bagaimana mengeluarkan perangkat lain saat akun dicurigai bocor, dan apa bedanya regenerate() dengan invalidate(). Pada chapter ini kita bedah session dari sisi authentication: datanya di mana, ID-nya kapan berputar, dan bagaimana mengelolanya lintas perangkat.
Session Driver dan Tabel sessions #
Konfigurasi SESSION_DRIVER menentukan tempat penyimpanan session. Driver database — yang dipakai sandbox kita — menulis setiap session ke tabel sessions yang migrasinya sudah tersedia bawaan:
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->string('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});Kolomnya jelas informatif: id adalah session ID, user_id terisi begitu pemilik session login, ip_address dan user_agent mencatat perangkat pemakai, dan payload memuat seluruh data session dalam bentuk ter-serialize. Status login sendiri tersimpan sebagai pasangan kunci di dalam payload: login_web_{hash} berisi ID user, dan password_hash_web berisi HMAC dari hash password. Dua kunci inilah yang dibaca SessionGuard di setiap request.
Aplikasi kita menulis data session lewat $request->session() — misalnya put(), get(), dan flash():
public function simpanSesi(Request $request)
{
$request->session()->put('keranjang', ['buku-laravel', 'mouse']);
return response('keranjang tersimpan di session');
}regenerate() vs invalidate() #
Dua method session ini sering tertukar. regenerate() mengganti session ID dengan yang baru tetapi mempertahankan seluruh data; invalidate() menghapus semua data dan mengganti ID. Logout yang benar memakai invalidate() — kita tidak ingin data lama ikut menempel pada ID session yang sama:
public function logout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/login');
}regenerateToken() di baris ketiga mengganti token CSRF di session — langkah penutup standar setelah logout. Perbandingan ringkasnya:
| Method | Session ID | Data session | Dipakai untuk |
|---|---|---|---|
regenerate() | diganti | dipertahankan | login, eskalasi hak |
invalidate() | diganti | dihapus semua | logout |
regenerateToken() | tetap | hanya token CSRF diganti | setelah logout |
Rotasi Session ID Saat Login #
Sebenarnya kita tidak perlu memanggil regenerate() secara manual saat login — SessionGuard sudah melakukannya. Di dalam Auth::attempt(), method login() menulis kunci login_web_* ke session lalu langsung memanggil $this->session->regenerate(true). Rotasi ini bukan formalitas: session ID yang tidak berputar saat login membuka celah session fixation, teknik penyerang yang menanamkan session ID buatan sebelum korban login. Feature test berikut membuktikan kedua rotasi tersebut beserta nasib data session:
$this->get('/keranjang/simpan'); // keranjang masuk ke session
$this->post('/login', [/* kredensial */]); // ID berputar, data tetap ada
$this->post('/logout'); // ID berputar lagi, data dihapus
Output yang Dihasilkan:
session_id: login_mengganti_id=ya, logout_mengganti_id=ya
regenerate: data_keranjang=["buku-laravel","mouse"]
invalidate: data_keranjang=nullTest tersebut menyimpan keranjang ke session, login, lalu logout. Setelah login ID session berubah dan keranjang selamat — itu regenerate(). Setelah logout ID berubah lagi dan keranjang lenyap — itu invalidate().
Mengeluarkan Perangkat Lain #
Fitur andalannya: Auth::logoutOtherDevices($password). Karena fitur ini membandingkan hash password di setiap session, kita wajib mengaktifkan middleware AuthenticateSession lewat bootstrap/app.php:
->withMiddleware(function (Middleware $middleware): void {
$middleware->redirectGuestsTo(fn () => route('login'));
$middleware->authenticateSessions();
})Route dan controller-nya meminta password aktif sebagai konfirmasi:
public function logoutDevices(Request $request)
{
$request->validate([
'current_password' => ['required', 'current_password'],
]);
Auth::logoutOtherDevices($request->input('current_password'));
return back()->with('status', 'Perangkat lain telah dikeluarkan.');
}Mekanismenya elegan: logoutOtherDevices() men-hash ulang password user (hash baru, password sama). Session di perangkat lain masih menyimpan password_hash_web versi lama, sehingga middleware AuthenticateSession menemukan ketidakcocokan dan memaksa logout pada request berikutnya. Password salah ditolak lebih dulu oleh rule current_password — test nyata menunjukkan ["The password is incorrect."].
Mengintip Sesi Aktif di Database #
Dengan driver database, “perangkat mana saja yang sedang login” adalah pertanyaan SQL biasa. Feature test berikut memainkan dua perangkat — aplikasi di-boot ulang lewat refreshApplication() untuk mensimulasikan session store kedua — lalu memeriksa tabelnya:
// Perangkat A login, lalu perangkat B login
$sesiSetelahA = DB::table('sessions')->count();
$this->refreshApplication();
$this->post('/login', [/* kredensial Budi */]);
$sesiSetelahB = DB::table('sessions')->count();
// Perangkat B mengeluarkan perangkat lain
$this->post('/logout-devices', ['current_password' => 'rahasia-budi-123']);Output yang Dihasilkan:
tabel_sessions: sesi_setelah_login_A=1, sesi_setelah_login_B=2, user_id_terisi=2
logout_other_devices: perangkat_B=200, perangkat_A=302, target_redirect_A=http://localhost:8000/loginBaris pertama membuktikan tabel merekam dua session untuk user yang sama. Baris kedua adalah klimaksnya: setelah perangkat B memanggil logoutOtherDevices(), perangkat B tetap menikmati dashboard (200), sementara perangkat A yang kembali memakai session cookie lamanya ditendang ke halaman login (302).
Dengan session aman terkelola, satu bata terakhir membangun benteng route kita: memahami middleware auth dan guest secara menyeluruh — redirect, intended URL, hingga guard khusus. Selengkapnya ada di dokumentasi Session
.