Episode ini membahas authentication dan authorization di SvelteKit: auth patterns yang umum dipakai, session handling dengan cookies dan server-side auth, protected routes dengan authorization guards, serta integrasi external auth providers seperti OAuth dan OIDC.

Hampir semua aplikasi web modern butuh membedakan siapa yang mengakses: halaman admin, profil pribadi, hingga data user. Episode 12 membahas authentication dan authorization di SvelteKit — dari pola auth yang umum dipakai, session handling dengan cookies, protected routes, hingga integrasi provider eksternal seperti OAuth dan OIDC.
Authentication menjawab pertanyaan "siapa kamu", sementara authorization menjawab "apa yang boleh kamu lakukan". Keduanya harus dipisahkan dengan jelas di arsitektur aplikasi. Di SvelteKit, kedua lapisan ini hidup di server: server actions, hooks, dan load functions.
Setelah episode ini, kalian bisa membangun login yang aman, melindungi route berdasarkan peran, dan menyambungkan akun dari provider pihak ketiga tanpa mengorbankan keamanan.
Pola yang paling umum di SvelteKit adalah session cookie: server membuat token, menyimpannya di cookie HTTP-only, lalu membaca token itu di setiap request lewat hooks. Token tidak pernah diserahkan ke JavaScript di browser sehingga tidak bisa dibaca oleh skrip yang disuntikkan.
Alternatifnya adalah token bearer seperti JWT yang dikirim lewat header Authorization. Pola ini cocok untuk API yang dikonsumsi aplikasi lain, tetapi menuntut kalian mengelola validitas dan masa berlaku token secara mandiri, termasuk revokasi yang lebih rumit.
import { fail } from "@sveltejs/kit";
import { buatSession } from "$lib/server/session";
export const actions = {
login: async ({ request, cookies }) => {
const form = await request.formData();
const email = String(form.get("email") ?? "");
const password = String(form.get("password") ?? "");
const user = await verifikasiKredensial(email, password);
if (!user) {
return fail(401, { error: "Email atau password salah" });
}
cookies.set("session", buatSession(user.id), {
httpOnly: true,
sameSite: "lax",
secure: true,
path: "/",
maxAge: 60 * 60 * 24 * 7
});
return { sukses: true };
}
};Cookie diatur dengan httpOnly: true agar tidak bisa diakses JavaScript, sameSite: "lax" untuk mengurangi risiko CSRF, dan secure: true saat berjalan di HTTPS. Masa berlaku default dibuat pendek; tambahkan mekanisme refresh jika session perlu bertahan lama.
Untuk aplikasi web yang diakses browser, session cookie adalah pilihan pertama. Gunakan token hanya jika ada kebutuhan khusus, misalnya API publik atau autentikasi antar layanan. Pastikan keputusan ini dituliskan di dokumentasi agar seluruh tim konsisten.
Semua verifikasi terpusat di satu tempat: hook handle di src/hooks.server.js. Hook berjalan untuk setiap request sebelum route diproses, sehingga hasil verifikasi bisa disimpan di event.locals dan dipakai di mana saja.
export const handle = async ({ event, resolve }) => {
const token = event.cookies.get("session");
if (token) {
const user = await verifikasiSession(token);
if (user) {
event.locals.user = user;
}
}
return await resolve(event);
};Penyimpanan session bisa di database (persisten dan mudah di-revoke) atau di token yang ditandatangani. Untuk aplikasi kecil, token bertanda tangan cukup; untuk aplikasi besar, simpan session di database dan acak ID-nya agar logout serta pemblokiran akun berjalan instan.
Deklarasikan bentuk locals di src/app.d.ts agar TypeScript tahu field apa yang tersedia. Tanpa deklarasi ini, akses ke event.locals.user tidak memiliki autocomplete dan bisa memicu error tipe yang membingungkan.
import type { User } from "$lib/types";
declare global {
namespace App {
interface Locals {
user?: User;
}
}
}
export {};Route yang hanya boleh diakses user terautentikasi memeriksa locals di load function dan melempar redirect bila tidak lolos. Dengan menaruh guard di +layout.server.js, semua route di bawahnya otomatis terlindungi.
import { redirect } from "@sveltejs/kit";
export const load = async ({ locals }) => {
if (!locals.user) {
throw redirect(303, "/login");
}
return { user: locals.user };
};Setelah user dikenali, kontrol akses berdasarkan peran memastikan halaman admin tidak bisa dibuka sembarang user. Bandingkan peran yang dimiliki dengan daftar peran yang diizinkan, dan kumpulkan kebijakan ini di satu helper agar mudah diubah.
import { redirect } from "@sveltejs/kit";
import { peranDiizinkan } from "$lib/server/otorisasi";
export const load = async ({ locals }) => {
const user = locals.user;
if (!user) {
throw redirect(303, "/login");
}
if (!peranDiizinkan(user.peran, ["admin", "editor"])) {
throw redirect(303, "/");
}
return { user };
};Jangan pernah mengandalkan hanya UI untuk otorisasi: tombol yang disembunyikan tidak menggantikan guard di server. Setiap load function dan server action yang menangani data sensitif wajib memeriksa kembali hak aksesnya.
Alih-alih mengelola password sendiri, banyak aplikasi memakai provider eksternal lewat OAuth atau OIDC: Google, GitHub, atau provider enterprise. Alurnya standar: aplikasi mengarahkan pengguna ke provider, provider mengembalikan kode, lalu aplikasi menukar kode itu dengan token.
import { redirect } from "@sveltejs/kit";
export const actions = {
loginProvider: async ({ cookies }) => {
const state = crypto.randomUUID();
cookies.set("oauth_state", state, { httpOnly: true, path: "/" });
const params = new URLSearchParams({
client_id: process.env.PROVIDER_CLIENT_ID,
redirect_uri: process.env.PROVIDER_REDIRECT_URI,
response_type: "code",
state,
scope: "openid profile email"
});
throw redirect(303, `https://provider.example/authorize?${params}`);
}
};Parameter state mencegah serangan CSRF pada callback; verifikasi harus dilakukan sebelum kode ditukar. Library seperti Auth.js mengelola alur ini beserta PKCE dan refresh token, sehingga kalian tidak perlu menulis ulang logika yang rawan kesalahan. Pasang dengan npm install @auth/sveltekit dan ikuti dokumentasi adapter untuk konfigurasi provider.
Token akses dan refresh disimpan di server, bukan di cookie client. Jangan pernah mengekspos token ke JavaScript di browser. Gunakan secret management melalui environment variable di server, rotasi token secara berkala, dan audit daftar aplikasi yang terhubung agar tidak ada akses yang terlupakan.
Inti yang harus dibawa pulang:
handle dan hasilnya disimpan di event.locals.state dan PKCE.Di episode 13 selanjutnya kita membahas secure data fetching: mengamankan request API dengan auth headers, handling secrets dan server-only config, perlindungan CSRF dan XSS, serta konfigurasi deployment yang aman.