Belajar Laravel - API Authentication (Sanctum)
Episode 18 of 24

Belajar Laravel - API Authentication (Sanctum)

Melindungi API dengan Laravel Sanctum: API tokens dan SPA authentication, trait HasApiTokens, authorization Bearer, token abilities/scope, serta perbandingan Sanctum vs Passport untuk OAuth.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Di episode 17 kita membangun REST API — tapi endpoint-nya belum dilindungi. Bagaimana cara memastikan hanya user yang sah yang bisa membuat atau mengubah data? Jawaban standar Laravel untuk ini adalah Sanctum: package resmi untuk API authentication yang ringan, lengkap, dan tidak serumit OAuth.

Di episode ini kita pasang Sanctum, memahami dua mode pemakaiannya (API token & SPA), lalu membandingkannya dengan Passport agar kalian tahu kapan memakai yang mana.

Mengapa Sanctum?

Sebelum Sanctum, API auth Laravel identik dengan Passport (OAuth2) — powerful tapi berat untuk kebutuhan umum. Sanctum hadir dengan dua mode:

  1. API tokens — token acak yang disimpan hashed, dikirim client di header Authorization: Bearer.
  2. SPA authentication — login via cookie session untuk frontend yang satu domain, tanpa token eksplisit.

Keduanya didukung oleh satu package yang ringan. Mari pasang.

Instalasi dan Konfigurasi

Install Sanctum
composer require laravel/sanctum
php artisan install:api
php artisan migrate

php artisan install:api melakukan setup lengkap: menambahkan HasApiTokens ke User, migration tabel personal_access_tokens, mengaktifkan route sanctum/csrf-cookie, dan membuat routes/api.php jika belum ada.

app/Models/User.php - aktifkan token
use Laravel\Sanctum\HasApiTokens;
 
class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}

API Tokens: Membuat dan Menggunakan

User membuat token — biasanya saat login di endpoint khusus:

Endpoint login yang mengembalikan token
use App\Models\User;
use Illuminate\Support\Facades\Hash;
 
public function login(Request $request)
{
    $request->validate([
        'email'    => 'required|email',
        'password' => 'required',
    ]);
 
    $user = User::where('email', $request->email)->first();
 
    if (!$user || !Hash::check($request->password, $user->password)) {
        return response()->json(['message' => 'Kredensial salah.'], 401);
    }
 
    $token = $user->createToken('app-client')->plainTextToken;
 
    return response()->json(['token' => $token]);
}

Client menyimpan token dan mengirimnya di setiap request:

Request dengan Bearer token
curl -H "Authorization: Bearer TOKEN" http://localhost:8000/api/posts

Token yang dikirim adalah plain text hanya sekali saat pembuatan — yang disimpan di database hanyalah hash-nya (via SHA-256). Kehilangan token = logout paksa: $user->tokens()->delete().

Melindungi Route API

Route API dipasangi middleware auth:sanctum:

routes/api.php
use App\Http\Controllers\Api\PostController;
 
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn ($request) => $request->user());
    Route::apiResource('posts', PostController::class);
});

Di controller, user yang terautentikasi diakses via $request->user(). Jika token tidak valid atau kadaluarsa, Laravel mengembalikan 401 secara otomatis.

Token Abilities / Scopes

Tidak semua token harus memiliki kekuatan penuh. Abilities membatasi apa yang bisa dilakukan sebuah token:

Buat token dengan abilities
$token = $user->createToken('mobile-app', ['posts:read', 'posts:create']);

Cek ability di route atau controller:

Memeriksa ability
Route::get('/posts', ...)->middleware('auth:sanctum')
    ->can('posts:read');
Cek ability di controller
public function destroy(Request $request, Post $post)
{
    if (!$request->user()->tokenCan('posts:delete')) {
        abort(403);
    }
    // ...
}

Pola ini penting untuk integrasi pihak ketiga: beri token dengan ability seminimal mungkin yang dibutuhkan — prinsip least privilege yang sama seperti izin di aplikasi.

Tip

Gunakan abilities untuk token milik pihak ketiga/device (misalnya token mobile yang hanya boleh baca). Untuk user biasa yang login di aplikasi kalian sendiri, cukup token polos tanpa ability — abilities menambah kompleksitas yang tidak perlu jika semua token berperilaku sama.

SPA Authentication Mode

Jika frontend kalian SPA (React/Vue/Inertia) di domain yang sama dengan backend, mode SPA lebih nyaman: tidak ada token yang dikelola manual, login memakai session cookie biasa.

  1. Pastikan domain frontend terdaftar di config/sanctum.php (stateful).
  2. Frontend memanggil GET /sanctum/csrf-cookie sebelum login.
  3. Login via POST /login biasa — session cookie ter-set otomatis.
  4. Route API dilindungi auth:sanctum seperti biasa.

Keuntungannya: tidak perlu menyimpan token di localStorage (yang rawan XSS), cookie httpOnly lebih aman. Kekurangannya: hanya bekerja untuk SPA satu origin — mobile app tetap butuh token.

Sanctum vs Passport

AspekSanctumPassport
TipeAPI tokens + SPA cookieOAuth2 penuh
FlowSederhana (token/hash)Authorization Code, PKCE, Client Credentials
Cocok untukAPI kalian sendiri, mobile appLogin via pihak ketiga (Google, GitHub)
KompleksitasRinganBerat
Kapan dipakaiDefault hampir semua kasusHanya jika butuh OAuth2 eksplisit

Note

Aturan praktis: mulai dengan Sanctum. Passport (OAuth2) baru diperlukan saat ada kebutuhan nyata seperti "aplikasi pihak ketiga login atas nama user" atau "access token dengan refresh token untuk integrasi eksternal". Membawa OAuth2 sejak awal hanya menambah kompleksitas tanpa manfaat.

Penutup

Inti yang harus dibawa pulang:

  • Sanctum = API tokens + SPA auth dalam satu package; pasang dengan install:api.
  • Token dibuat dengan createToken(), dikirim via header Authorization: Bearer.
  • Lindungi route dengan auth:sanctum; batasi token dengan abilities.
  • Mode SPA memakai cookie session, aman dari XSS token-theft.
  • Sanctum untuk mayoritas kasus; Passport hanya saat OAuth2 benar-benar dibutuhkan.

Di episode 19 selanjutnya kita akan membahas Reverb WebSocket real-time — konfigurasi Laravel Reverb, broadcasting dengan ShouldBroadcast, Reverb DB driver (v13), dan client Echo untuk notifikasi/chat real-time. Sampai jumpa di episode 19!