Memahami locals.auth() dan event.locals.auth() di SvelteKit: Beserta Contoh Penerapannya -> Svelte Clerk


Pendahuluan
Dalam pengembangan aplikasi web modern dengan SvelteKit dan Svelte Clerk, kita sering menemukan dua cara untuk mengakses fungsi autentikasi: locals.auth()
dan event.locals.auth()
. Meskipun keduanya terlihat mirip, mereka memiliki konteks penggunaan yang berbeda dan penting untuk dipahami agar dapat mengimplementasikan autentikasi dengan benar.
Asal-usul Fungsi auth()
Svelte Clerk sebagai Provider
Fungsi auth()
berasal dari library Svelte Clerk, yang merupakan wrapper untuk Clerk.com - layanan autentikasi modern. Svelte Clerk menyediakan integrasi seamless antara Clerk dan SvelteKit.
// hooks.server.ts
import { withClerkHandler } from 'svelte-clerk/server';
export const handle: Handle = sequence(
withClerkHandler(), // ← Ini yang menambahkan auth() ke locals
// ... middleware lainnya
);
Type Definition
Svelte Clerk menambahkan type definition untuk auth()
di interface Locals
:
// app.d.ts
interface Locals {
auth: import('svelte-clerk/server').RequestAuth;
}
// RequestAuth adalah function yang mengembalikan session
type RequestAuth = () => Promise<{
userId?: string;
sessionId?: string;
// ... data session lainnya
}>;
Perbedaan locals.auth()
vs event.locals.auth()
1. event.locals.auth()
- Konteks Hooks/Middleware
Digunakan di: Handle
functions dalam hooks.server.ts
Konteks: Server-side middleware dan hooks Parameter: event
object dari SvelteKit
// hooks.server.ts
const authMiddleware: Handle = async ({ event, resolve }) => {
const session = await event.locals.auth(); // ← event.locals
if (session?.userId) {
const user = await checkUserStatus(session.userId);
event.locals.user = user;
}
return resolve(event);
};
2. locals.auth()
- Konteks Page/Layout
Digunakan di: load
functions dalam page.server.ts
atau layout.server.ts
Konteks: Page/Layout server load functions Parameter: locals
object yang sudah di-extract dari event
// page.server.ts
export async function load({ locals }) {
const session = await locals.auth(); // ← locals (sudah di-extract)
const user = locals.user;
return { user };
}
Alur Data dan Eksekusi
1. Request Flow
// 1. Request masuk ke SvelteKit
Request → hooks.server.ts
// 2. withClerkHandler() menambahkan auth() ke event.locals
withClerkHandler() → event.locals.auth()
// 3. Middleware kita akses via event.locals
const session = await event.locals.auth();
// 4. SvelteKit extract locals untuk page.server.ts
export async function load({ locals }) {
// locals adalah event.locals yang sudah di-extract
const session = await locals.auth();
}
2. Sequence Execution
export const handle: Handle = sequence(
dbErrorMiddleware,
withClerkHandler(), // ← Menambahkan auth() ke event.locals
authMiddleware, // ← Menggunakan event.locals.auth()
handleParaglide
);
Implementasi Praktis
1. Hooks Server dengan Authentication Middleware
// hooks.server.ts
import { withClerkHandler } from 'svelte-clerk/server';
import { checkUserStatus } from '$lib/server/middleware/auth';
const authMiddleware: Handle = async ({ event, resolve }) => {
const session = await event.locals.auth();
if (session?.userId) {
try {
const user = await checkUserStatus(session.userId);
event.locals.user = user; // ← Set user data untuk digunakan di page
} catch (error) {
console.error('Error loading user data:', error);
}
}
return resolve(event);
};
export const handle: Handle = sequence(
withClerkHandler(),
authMiddleware,
// ... middleware lainnya
);
2. Page Server Load Function
// page.server.ts
export async function load({ locals }) {
const session = await locals.auth();
const user = locals.user; // ← Data yang diset di hooks
if (!user) {
throw redirect(302, '/login');
}
return { user };
}
3. Type Safety dengan TypeScript
// app.d.ts
import type { AuthUser } from '$lib/server/middleware/auth';
interface Locals {
auth: import('svelte-clerk/server').RequestAuth;
user?: AuthUser; // ← Custom user data
}
// TypeScript memberikan autocomplete dan type checking
const session = await locals.auth(); // ← Type: Promise<Session>
const user = locals.user; // ← Type: AuthUser | undefined
Best Practices
1. Gunakan Hooks untuk Data Loading
// ✅ Baik: Load user data sekali di hooks
const authMiddleware: Handle = async ({ event, resolve }) => {
const session = await event.locals.auth();
if (session?.userId) {
const user = await checkUserStatus(session.userId);
event.locals.user = user;
}
return resolve(event);
};
// ❌ Buruk: Load user data di setiap page
export async function load({ locals }) {
const session = await locals.auth();
const user = await checkUserStatus(session.userId); // ← Duplikasi
return { user };
}
2. Validasi di Page Server
// ✅ Baik: Validasi role/status di page server
export async function load({ locals }) {
const user = requireAdmin(locals); // ← Helper function
return { user };
}
// Helper function untuk validasi
export function requireAdmin(locals: any): AuthUser {
if (!locals.user) {
throw redirect(302, '/login');
}
if (locals.user.role !== 'admin') {
throw redirect(302, '/dashboard');
}
return locals.user;
}
3. Error Handling
// hooks.server.ts
const authMiddleware: Handle = async ({ event, resolve }) => {
try {
const session = await event.locals.auth();
if (session?.userId) {
const user = await checkUserStatus(session.userId);
event.locals.user = user;
}
} catch (error) {
console.error('Auth middleware error:', error);
// Jangan fail request, lanjutkan tanpa user data
}
return resolve(event);
};
Alur Kerja
// 1. Request masuk ke SvelteKit
Request → hooks.server.ts
// 2. withClerkHandler() menambahkan auth() ke event.locals
withClerkHandler() → event.locals.auth()
// 3. Middleware kita akses via event.locals
const session = await event.locals.auth();
// 4. SvelteKit extract locals untuk page.server.ts
export async function load({ locals }) {
// locals adalah event.locals yang sudah di-extract
const session = await locals.auth();
}
Kesimpulan
event.locals.auth()
: Digunakan di hooks/middleware untuk mengakses session dan memuat data userlocals.auth()
: Digunakan di page.server.ts untuk mengakses session yang sudah dimuatKeduanya sama: Mengakses function yang sama dari Svelte Clerk
Perbedaan konteks: Berbeda cara akses berdasarkan tempat penggunaannya
Pattern ini memungkinkan kita untuk:
Performance: Load user data sekali di hooks, bukan di setiap page
Consistency: User data tersedia di semua request
Type Safety: TypeScript support dengan proper type definitions
Maintainability: Logic terpusat dan mudah dikelola
Dengan memahami perbedaan ini, kita dapat mengimplementasikan sistem autentikasi yang efisien dan maintainable di aplikasi SvelteKit kita.
Subscribe to my newsletter
Read articles from Sandikodev directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
