Episode ini membahas keamanan identitas pengguna: pola auth di SvelteKit, session management dan secure cookies, protected routes dan route guards, serta role-based access control dan auth di sisi klien dan server.

Aplikasi yang berisi data pengguna wajib tahu siapa yang sedang menggunakannya. Identitas itu menentukan apa yang boleh dilihat dan diubah. Tanpa lapisan auth yang benar, endpoint yang seharusnya privat bisa dibaca siapa saja.
Auth adalah dua hal yang berbeda. Authentication memverifikasi identitas — siapa kamu — sementara authorization menentukan hak akses — apa yang boleh kamu lakukan. SvelteKit tidak mengirimkan solusi auth bawaan, tetapi menyediakan semua primitif untuk membangunnya: cookies, hooks, dan load functions.
Episode ini membahas pola auth di SvelteKit, session management dan secure cookies, protected routes dan route guards, serta role-based access control dan auth di sisi klien dan server. Setelah selesai, kalian bisa membangun sistem login yang aman untuk aplikasi produksi.
Tidak seperti framework monolitik, SvelteKit memberi kebebasan memilih mekanisme auth. Dua pola yang paling sering dipakai adalah session-based auth dan token-based auth. Pola pertama menyimpan session di server dan mengirim cookie berisi token, sementara pola kedua membawa token yang ditandatangani di header Authorization.
Session-based auth sederhana, mudah dicabut, dan cocok untuk mayoritas aplikasi. Token-based auth lebih pas untuk API publik, dengan trade-off bahwa token sulit dibatalkan sebelum kedaluwarsa.
Kalian bisa menulisnya dari nol. Hash password menggunakan bcryptjs:
npm install bcryptjsAlur paling umum di SvelteKit dimulai dari form login di komponen, dilanjutkan form action di server, lalu cookie session. Form action berjalan penuh di server, sehingga password tidak pernah masuk ke JavaScript klien. Inilah alasan utama SvelteKit menyarankan form actions untuk autentikasi.
Cookie adalah tempat penyimpanan session paling praktis, asalkan atribut keamanannya benar:
import { redirect } from "@sveltejs/kit"
export const actions = {
async login({ request, cookies }) {
const data = await request.formData()
const email = data.get("email")
const token = await buatToken(email)
cookies.set("session", token, {
httpOnly: true,
secure: true,
sameSite: "lax",
path: "/",
maxAge: 60 * 60 * 24 * 7,
})
throw redirect(303, "/dashboard")
},
}httpOnly: true membuat cookie tidak bisa dibaca JavaScript, sehingga menangkal serangan XSS yang mencoba mencuri session. secure: true memaksa cookie hanya dikirim lewat HTTPS, dan sameSite: "lax" melindungi dari serangan CSRF. Kombinasi ini adalah standar minimum untuk cookie auth.
handle di hooks.server.js berjalan sebelum setiap request. Di sinilah token diubah menjadi objek user yang bisa diakses semua load function dan form action:
import { verifikasiSession } from "$lib/server/session"
export async function handle({ event, resolve }) {
const token = event.cookies.get("session")
event.locals.user = token
? await verifikasiSession(token)
: null
return resolve(event)
}event.locals.user berisi null saat tidak login dan objek user saat session valid. Dengan pola ini, seluruh aplikasi membaca identitas dari satu sumber, tanpa tiap halaman memvalidasi token berulang kali.
Halaman yang butuh login tidak boleh hanya bersembunyi di tampilan. Guard harus berjalan di server sebelum halaman dirender:
import { redirect } from "@sveltejs/kit"
export async function load({ locals }) {
if (!locals.user) {
throw redirect(303, "/masuk")
}
return { user: locals.user }
}Melempar redirect di load function adalah cara idiomatis SvelteKit untuk mengalihkan pengguna yang belum login. Karena +page.server.js berjalan di server, pengguna tidak bisa menghindarinya lewat DevTools.
Saat banyak halaman membutuhkan proteksi yang sama, taruh guard di +layout.server.js induknya. Sekali diletakkan di layout, seluruh rute turunan otomatis terlindungi. Pola ini menghindari duplikasi kode antar halaman dan memudahkan perubahan kebijakan akses.
Setelah user terautentikasi, authorization menentukan hak akses berdasarkan peran:
import { error } from "@sveltejs/kit"
export function requireRole(user, role) {
if (!user || !user.roles.includes(role)) {
throw error(403, "Akses ditolak")
}
}user.roles.includes(role) mengecek apakah peran yang dibutuhkan ada di daftar peran user. Saat tidak terpenuhi, fungsi melempar 403 Forbidden. Pemeriksaan ini sebaiknya selalu di server — klien bisa diperdaya dengan mengubah respons.
Di sisi klien, auth berfungsi untuk pengalaman: menyembunyikan tombol admin, menampilkan nama user, atau mengalihkan ke halaman login:
<script>
import { onMount } from "svelte"
import { goto } from "$app/navigation"
let { data } = $props()
onMount(() => {
if (!data.user) {
goto("/masuk")
}
})
</script>Guard klien ini hanya untuk pengalaman, bukan keamanan. Karena berjalan setelah halaman dimuat, konten sensitif tetap harus dilindungi di server. goto("/masuk") mengalihkan pengguna tanpa memuat ulang halaman.
Inti yang harus dibawa pulang:
httpOnly, secure, dan sameSite.hooks.server.js dan injeksi ke event.locals.+page.server.js atau +layout.server.js dengan redirect.Di episode 13 selanjutnya kita akan membahas secure data fetching — konsumsi API yang aman dan penanganan token, CSRF, XSS, dan sanitasi input, serta praktik terbaik untuk data sensitif. Session dari episode ini menjadi kunci yang melindungi setiap request API.