Laravel Sanctum adalah package autentikasi ringan yang menangani dua skenario paling umum dalam aplikasi modern: token-based authentication untuk mobile app / third-party API consumers, dan cookie-based session authentication untuk SPA (Single Page Application). Artikel ini membahas implementasi keduanya secara lengkap.

Kapan Memilih Sanctum vs Passport?

Laravel punya dua package autentikasi utama:

  • Sanctum — Ringan, untuk aplikasi yang Anda sendiri yang buat (first-party). Cocok untuk SPA + mobile app milik sendiri.
  • Passport — Full OAuth2 server, untuk skenario third-party authorization (seperti "Login with App X"). Lebih kompleks dan berat.

Untuk 90% kasus, Sanctum sudah lebih dari cukup.

Instalasi dan Setup

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

Tambahkan HasApiTokens trait ke model User:

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}

Skenario 1: Token Auth untuk Mobile / API Client

Cocok untuk aplikasi mobile (Flutter, React Native) atau klien API eksternal.

Login — Issue Token

class AuthController extends Controller
{
    public function login(LoginRequest $request): JsonResponse
    {
        if (! Auth::attempt($request->only('email', 'password'))) {
            return response()->json(['message' => 'Invalid credentials'], 401);
        }

        $user = Auth::user();
        $token = $user->createToken(
            name: $request->device_name ?? 'api',
            abilities: ['*'],
            expiresAt: now()->addDays(30),
        )->plainTextToken;

        return response()->json([
            'user'  => new UserResource($user),
            'token' => $token,
        ]);
    }

    public function logout(Request $request): JsonResponse
    {
        $request->user()->currentAccessToken()->delete();
        return response()->json(['message' => 'Logged out']);
    }
}

Protect Routes

// routes/api.php
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn (Request $r) => new UserResource($r->user()));
    Route::apiResource('/posts', PostController::class);
});

Penggunaan dari Client

// Header setiap request
Authorization: Bearer 1|abc123xyz...

Skenario 2: SPA Authentication dengan Cookies

Untuk SPA Vue/React yang di-serve dari domain yang sama atau subdomain. Lebih aman dari token karena tidak menyimpan token di localStorage (rentan XSS).

Setup CORS dan Session

// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    Sanctum::currentApplicationUrlWithPort()
))),

Flow SPA Auth

  1. SPA memanggil GET /sanctum/csrf-cookie untuk mendapatkan CSRF token
  2. SPA mengirim POST ke /login dengan credentials
  3. Laravel set session cookie, SPA sudah authenticated
  4. Setiap request berikutnya otomatis terautentikasi via cookie
// Axios setup di Vue/React
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;

// Login
await axios.get('/sanctum/csrf-cookie');
await axios.post('/login', { email, password });

Token Abilities (Scope)

Sanctum mendukung pembatasan kemampuan token:

// Issue token dengan abilities terbatas
$token = $user->createToken('readonly-token', ['posts:read', 'comments:read']);

// Check di controller
if (! $request->user()->tokenCan('posts:write')) {
    abort(403, 'Token tidak memiliki izin write');
}

Best Practices Keamanan

  • Selalu set expiration time pada token — jangan buat token yang tidak pernah expired
  • Hapus semua token saat user ganti password: $user->tokens()->delete()
  • Gunakan HTTPS di production — token di header HTTP bisa disadap tanpa TLS
  • Untuk SPA, gunakan cookie-based auth (lebih aman dari localStorage)
  • Implementasikan rate limiting di route auth untuk mencegah brute force

Rate Limiting

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->throttleApi();
})

// Atau custom di routes
Route::middleware(['auth:sanctum', 'throttle:60,1'])->group(function () {
    // ...
});

Sanctum menyederhanakan autentikasi API tanpa overhead OAuth2 penuh. Untuk aplikasi yang Anda sendiri yang control client-nya, Sanctum adalah pilihan yang tepat dan cukup aman jika diimplementasikan dengan benar.