Di Section Authentication dan Authorization, kita membangun login dari nol: hash password dengan password_hash(), simpan user id ke session, regenerate id session setelah login, dan tulis middleware pemeriksa sendiri. Setiap langkah itu adalah titik rawan salah yang bisa membuka celah keamanan. Laravel membungkus seluruh alur tersebut menjadi sistem authentication teruji — dan lebih penting lagi, kode yang bisa kita baca. Pada chapter penutup Laravel ini kita bedah starter kit, guard dan provider, login lewat facade, middleware auth, authorization dengan gate dan policy, hashing, verifikasi email, hingga token API Sanctum.
Starter Kit Breeze #
Rakit sendiri atau pakai scaffolding? Untuk belajar, jawaban terbaik adalah keduanya: kita sudah merakit sendiri, sekarang pakai hasil rakitan Laravel dan pahami isinya. Breeze adalah starter kit resmi paling ringkas yang memasang kerangka lengkap halaman login, registrasi, reset password, dan verifikasi email.
composer require laravel/breeze --dev
php artisan breeze:install blade
npm install && npm run dev
php artisan migrateEmpat langkah di atas menuliskan controller autentikasi ke app/Http/Controllers/Auth/, view Blade ke resources/views/auth/, dan rute login-registrasi ke routes/auth.php. Breeze bukan kotak hitam: seluruh kodenya adalah Laravel biasa yang bisa kita baca dan ubah — method attempt(), redirect, dan validasi yang kita pelajari di chapter-chapter sebelumnya. Setelah php artisan migrate membuat tabel-tabelnya, halaman /register dan /login langsung berfungsi. Selain Breeze ada juga starter kit yang lebih tebal seperti Jetstream (dengan dua faktor autentikasi dan manajemen tim); mulailah dari Breeze karena paling dekat dengan materi kita.
Migrasi Tabel users #
Tabel users bawaan Laravel sudah menunjukkan praktik aman lewat skemanya sendiri:
<?php
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});Tiga kolom layak diperhatikan. Kolom email diberi constraint unique — integritas di level database, bukan hanya validasi form. Kolom password bertipe VARCHAR karena yang disimpan adalah hash bcrypt sepanjang 60 karakter, bukan teks sandi asli — persis praktik Password Hash
. Kolom email_verified_at menyimpan waktu verifikasi; null berarti belum terverifikasi, dan kolom remember_token menampung token acak untuk fitur remember me di Remember Me
.
Guard dan Provider #
Konfigurasi autentikasi Laravel berpusat pada dua istilah: guard dan provider. Guard menentukan bagaimana pengguna diautentikasi pada tiap permintaan; provider menentukan dari mana data pengguna diambil.
<?php
// potongan config/auth.php
return [
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
];Konfigurasi di atas berbunyi: guard bernama web memakai driver session, dan mencari identitas lewat provider users yang sumbernya model Eloquent User. Inilah persis arsitektur Session-Based Authentication
yang kita bangun manual — user id disimpan di session, tiap permintaan berikutnya membaca id itu lalu memuat user dari database. Kita bisa mendaftarkan guard tambahan (misalnya guard token untuk API) dan provider alternatif tanpa mengubah guard pertama; inilah yang membuat satu aplikasi bisa melayani sesi browser dan token mobile sekaligus.
Login dengan Auth Facade #
Proses login inti dijalankan oleh Auth::attempt(): mencari user berdasarkan kredensial, membandingkan password melalui hash, lalu menyimpan identitas ke session.
<?php
use Illuminate\Support\Facades\Auth;
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required|string',
]);
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return redirect()->intended('/dashboard');
}
return back()->withErrors([
'email' => 'Kredensial tidak cocok dengan data kami.',
]);Mari kita bedah alurnya:
Auth::attempt($credentials): mencari user dengan email tersebut, lalu menjalankan pembanding hash terhadap kolom password — padananpassword_verify()dari chapter password hashing, termasuk kebalannya terhadap timing attack.$request->session()->regenerate(): mengganti id session setelah login sukses. Langkah ini mencegah session fixation seperti kita bahas di Session Fixation ; melewatinya adalah celah klasik pada login buatan sendiri.redirect()->intended('/dashboard'): mengembalikan pengguna ke URL yang sempat ingin dibukanya sebelum dipaksa login, atau ke/dashboardbila tidak ada.
Setelah login, identitas tersedia di mana saja melalui Auth::user() (instance User), Auth::id() (id-nya), dan Auth::logout() untuk keluar — yang juga sebaiknya diikuti $request->session()->invalidate() agar session lama tidak dipakai ulang.
Melindungi Route dengan Middleware auth #
Rute privat dilindungi dengan middleware auth, konsep yang identik dengan lapisan middleware yang kita tulis di Middleware
— hanya saja sudah tersedia dalam satu kata.
<?php
use App\Http\Controllers\DashboardController;
use Illuminate\Support\Facades\Route;
Route::get('/dashboard', [DashboardController::class, 'index'])
->middleware('auth');Middleware auth memeriksa guard web: bila session berisi identitas yang valid, permintaan diteruskan ke controller; bila tidak, pengguna dialihkan ke rute bernama login. Untuk guard selain session — misalnya token API — penolakan dijawab dengan 401 Unauthorized alih-alih redirect, karena klien API tidak mengerti halaman login. Dalam controller, pengguna berjalan tersedia lewat $request->user() tanpa query tambahan karena middleware sudah memuatnya.
Authorization dengan Gate dan Policy #
Authentication menjawab “siapa Anda”; authorization menjawab “apa yang boleh Anda lakukan” — pembedaan yang kita tetapkan di Authentication vs Authorization . Laravel menyediakan dua alat: gate untuk kemampuan tunggal, dan policy untuk kumpulan aturan per model.
<?php
use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->author_id;
});<?php
// app/Policies/PostPolicy.php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function update(User $user, Post $post): bool
{
return $user->id === $post->author_id;
}
}Class PostPolicy untuk model Post ditemukan otomatis lewat konvensi penamaan App\Policies\PostPolicy — tidak perlu registrasi manual. Nama method dipetakan menjadi kemampuan dengan nama yang sama, sehingga pemeriksaan di controller dan Blade memakai satu istilah:
<?php
// di controller
if ($request->user()->can('update', $post)) {
$post->update($validated);
}<!-- di template Blade -->
@can('update', $post)
<a href="{{ route('posts.edit', $post->id) }}">Sunting Artikel</a>
@endcanClosure dan method policy menerima user berjalan plus model terkait, lalu mengembalikan bool — tempat logika kepemilikan seperti di atas ditulis. Untuk kontrol berbasis peran sistemik (admin, editor, penonton), pola Gate::before() atau kolom peran pada user melengkapi policy — pembahasan mendalamnya ada di Role-Based Access Control
.
Hashing Password #
Laravel memusatkan operasi hash pada facade Hash yang di balik layar membungkus password_hash() dan password_verify() yang sudah kita kuasai.
<?php
use Illuminate\Support\Facades\Hash;
// saat registrasi: simpan hash, bukan sandi asli
$user = User::create([
'name' => 'Budi',
'email' => '[email protected]',
'password' => Hash::make('rahasia-pengguna'),
]);
// saat login atau ganti password: bandingkan
if (Hash::check('rahasia-pengguna', $user->password)) {
// password cocok
}Algoritma bawaannya adalah bcrypt dengan cost yang bisa dikonfigurasi lewat config/hashing.php, dan driver argon2id tersedia bila server mendukungnya. Satu aturan yang tidak berubah dari chapter Password Hashing: hasil Hash::make() terhadap teks yang sama berbeda setiap panggilan karena salt acak, sehingga pembandingan wajib lewat Hash::check(), bukan perbandingan string. Karena framework sudah mengurus cost dan algoritma, fokus kita tinggal satu: jangan pernah menyimpan sandi asli.
Verifikasi Email Bawaan #
Untuk memastikan alamat email benar-benar milik pendaftar, Laravel menyediakan alur verifikasi yang tinggal diaktifkan: model User mengimplementasikan interface MustVerifyEmail.
<?php
// app/Models/User.php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable;
}<?php
use App\Http\Controllers\DashboardController;
use Illuminate\Support\Facades\Route;
Route::get('/dashboard', [DashboardController::class, 'index'])
->middleware(['auth', 'verified']);Dengan interface tersebut, event registrasi memicu pengiriman tautan verifikasi bertanda tangan (signed URL) ke email pendaftar; klik tautan mengisi kolom email_verified_at. Middleware verified kemudian menolak pengguna yang belum verifikasi — pola alurnya sama dengan yang kita rancang di Email Verification
, lengkap dengan tanda tangan URL yang tidak bisa dipalsukan.
Token API dengan Sanctum #
Aplikasi web memakai session; klien API memakai token. Sanctum adalah paket resmi Laravel untuk token API personal, dan alurnya sejajar dengan API Token Authentication
yang kita bangun manual: token diterbitkan per pengguna, disimpan sebagai hash di database, dan dikirim klien pada header Authorization: Bearer.
php artisan install:api<?php
// di controller, setelah pengguna login melalui guard web
$token = $request->user()->createToken('aplikasi-mobile');
echo $token->plainTextToken; // hanya tampil sekali saat penerbitan
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/profil', function (Request $request) {
return $request->user();
});Perintah install:api memasang Sanctum sekaligus berkas routes/api.php, dan middleware auth:sanctum mengganti driver pemeriksaan dari session menjadi token. Perhatikan bahwa createToken() mengembalikan token yang hanya bisa dibaca sekali: yang tersimpan di tabel personal_access_tokens adalah hash-nya, dan plainTextToken wajib langsung ditunjukkan ke pengguna karena tidak bisa diperlihatkan lagi — perilaku yang sama seperti API key di chapter api-token. Sanctum juga mendukung mode cookie untuk SPA: aplikasi JavaScript di subdomain yang sama bisa memakai session browser alih-alih mengelola token sendiri.
Ringkasan #
Kita kini menuntaskan tur Laravel: starter kit Breeze memberi kerangka autentikasi yang bisa dibaca, guard dan provider memisahkan mekanisme sesi dari sumber identitas, Auth::attempt() menjalankan login yang aman berikut regenerate session, middleware auth menjaga rute privat, gate dan policy menegakkan authorization per kemampuan, Hash membungkus bcrypt dengan aman, verifikasi email aktif lewat satu interface, dan Sanctum membawa autentikasi ke dunia API. Dari routing sampai token, semua fitur Laravel yang kita bedah ternyata otomasi atas konsep yang pernah kita tulis dengan tangan. Dengan bekal itu, section berikutnya mengajak kita menimbang framework kedua — Symfony — yang membangun fondasi dengan filosofi berbeda: komponen yang bisa dipakai terpisah dari framework utuhnya.