16. Auth Strategy: Cookies vs LocalStorage
A. Perbandingan: Cookie (HttpOnly) vs LocalStorage
Pilihan penyimpanan token berdampak langsung pada keamanan dan cara HTTP client mengirim token ke backend.
| Aspek | Cookie (HttpOnly) | LocalStorage |
|---|---|---|
| Ketahanan XSS | ✅ Aman — JS tidak bisa membaca | ❌ Rentan — JS bisa baca langsung |
| Dukungan SSR / RSC | ✅ Terbaca server (proxy.js / RSC) | ❌ Hanya ada di browser |
| CSRF | Perlu flag SameSite=Lax atau Strict | Kebal (tidak auto-terkirim) |
| Token dikirim ke API | Otomatis oleh browser (withCredentials) | Manual — harus diambil & diset di header |
| Penggunaan | Token autentikasi sesi | UI preference (tema, sidebar state) |
Aturan: Token autentikasi wajib di Cookie (HttpOnly). LocalStorage hanya untuk data non-sensitif seperti tema atau preferensi sidebar.
B. Hubungan Cookie dengan API Instance (APIInstance)
Cara cookie dikirim ke backend bergantung pada satu flag krusial di APIInstance:
// services/api.ts
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
withCredentials: true, // ← KUNCI: browser otomatis lampirkan HttpOnly Cookie
});
Dengan withCredentials: true:
- Browser otomatis melampirkan semua cookie (termasuk HttpOnly) ke setiap request
- Tidak perlu lagi
getCookie("accessToken")secara manual di interceptor - Backend menerima cookie langsung — tidak perlu
Authorization: Bearerheader
Dengan Fetch API, gunakan credentials: "include":
// Setara withCredentials: true untuk Fetch API
fetch("/api/users", {
credentials: "include", // ← sama dengan withCredentials: true
});
Alur kerja end-to-end:
Login → Server set HttpOnly Cookie → Browser simpan cookie
↓
Request ke /api/* → Browser lampirkan cookie otomatis (withCredentials)
↓
Backend baca cookie, validasi sesi
C. Auth Libraries: Perbandingan & Kapan Digunakan
Update penting: Tim NextAuth.js telah resmi bergabung ke Better Auth (tertera di banner docs resmi NextAuth.js: "NextAuth.js is now part of Better Auth"). Artinya Better Auth adalah penerus resmi NextAuth.js. NextAuth.js v4 masih bisa digunakan di project lama, namun tidak disarankan untuk project baru.
1. Better Auth ⭐ (Rekomendasi — Penerus NextAuth.js)
Library auth modern yang dibangun dari awal dengan pendekatan framework-agnostic dan TypeScript-first. Tim NextAuth.js telah resmi bergabung ke proyek ini, menjadikannya ekosistem auth tunggal yang direkomendasikan. Mengelola sesi via HttpOnly Cookie secara otomatis — tidak perlu menulis interceptor refresh token.
// lib/auth-client.ts
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_APP_URL,
});
export const { useSession, signIn, signUp, signOut } = authClient;
// Penggunaan di komponen — cookie terkirim otomatis via APIInstance
import { useSession, signOut } from "@/lib/auth-client";
import APIInstance from "@/services/api";
export function UserProfileCard() {
const { data: session, isPending } = useSession();
if (isPending) return <div>Memverifikasi sesi...</div>;
if (!session) return <div>Silakan login terlebih dahulu.</div>;
return (
<div>
<p>Selamat datang, {session.user.name}</p>
<p>Role: {session.user.role}</p>
<button
onClick={() =>
signOut({
fetchOptions: {
onSuccess: () => {
window.location.href = "/login";
},
},
})
}
>
Keluar
</button>
</div>
);
}
| ✅ Kelebihan | Framework-agnostic (Next.js & Vite), HttpOnly Cookie otomatis, TypeScript-first, built-in RBAC & session management, tidak perlu server khusus |
| ❌ Kekurangan | Library lebih baru (komunitas lebih kecil dari NextAuth), memerlukan backend adapter sendiri |
2. NextAuth.js (Legacy — Tidak Disarankan untuk Project Baru)
NextAuth.js adalah library auth yang paling banyak dipakai di ekosistem Next.js sebelumnya. Namun per 2025, tim NextAuth.js telah resmi bergabung ke Better Auth. NextAuth.js tidak lagi dikembangkan secara aktif sebagai proyek terpisah.
Gunakan NextAuth.js hanya untuk maintain project lama. Untuk project baru, migrasi ke Better Auth.
// app/api/auth/[...nextauth]/route.ts (Next.js — Legacy)
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
export const { handlers, auth } = NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
],
});
| ✅ Kelebihan | Komunitas besar, 40+ OAuth provider built-in, banyak referensi & tutorial tersedia |
| ❌ Kekurangan | Tidak aktif dikembangkan lagi (tim bergabung ke Better Auth), tidak disarankan untuk project baru, RBAC manual |
3. Custom JWT (Manual)
Pendekatan manual: token JWT disimpan di Cookie (HttpOnly), dikirim lewat APIInstance, dan di-refresh via endpoint /auth/refresh.
// services/api.ts — interceptor refresh token manual
let isRefreshing = false;
api.interceptors.response.use(
(res) => res,
async (error) => {
if (error.response?.status === 401 && !error.config._retry) {
error.config._retry = true;
if (!isRefreshing) {
isRefreshing = true;
try {
// Minta token baru — cookie refresh token dikirim otomatis
await api.post("/auth/refresh");
isRefreshing = false;
return api(error.config); // Ulangi request asal
} catch {
isRefreshing = false;
window.location.href = "/login";
}
}
}
return Promise.reject(error);
},
);
| ✅ Kelebihan | Kontrol penuh atas alur token, tidak ada dependency eksternal, fleksibel untuk backend apapun |
| ❌ Kekurangan | Harus tulis sendiri semua logic (refresh, expiry, rotation), rentan bug jika tidak hati-hati, lebih banyak boilerplate |
4. Clerk
Auth-as-a-Service yang fully managed. Tidak perlu backend auth sama sekali — semua dikelola di cloud Clerk.
// Wrap aplikasi dengan ClerkProvider
import { ClerkProvider, SignedIn, SignedOut, UserButton } from "@clerk/nextjs";
export default function RootLayout({ children }) {
return (
<ClerkProvider>
<SignedIn>
<UserButton /> {/* Komponen siap pakai */}
{children}
</SignedIn>
<SignedOut>
<RedirectToSignIn />
</SignedOut>
</ClerkProvider>
);
}
| ✅ Kelebihan | Setup tercepat (hitungan menit), UI komponen siap pakai, multi-factor auth & social login built-in, managed sepenuhnya |
| ❌ Kekurangan | Berbayar untuk skala besar, data user disimpan di server Clerk (bukan server kita), vendor lock-in, kurang fleksibel untuk kasus enterprise custom |
D. Matriks Keputusan: Pilih Library yang Tepat
| Kriteria | Better Auth ⭐ | NextAuth.js (Legacy) | Custom JWT | Clerk |
|---|---|---|---|---|
| Bekerja di Next.js | ✅ | ✅ | ✅ | ✅ |
| Bekerja di Vite (React) | ✅ | ❌ | ✅ | ✅ |
| HttpOnly Cookie otomatis | ✅ | ✅ | Manual | ✅ |
| RBAC built-in | ✅ | ❌ Manual | Manual | ✅ |
| OAuth (Google, GitHub, dll) | ✅ | ✅ Terbaik | Manual | ✅ |
| Refresh token otomatis | ✅ | ✅ | Manual | ✅ |
| Aktif dikembangkan | ✅ | ❌ Tidak lagi | ✅ | ✅ |
| Data user di server sendiri | ✅ | ✅ | ✅ | ❌ |
| Gratis tanpa batas | ✅ | ✅ | ✅ | ⚠️ |
| Kompleksitas setup | Rendah | Sedang | Tinggi | Sangat Rendah |
⚠️ NextAuth.js tidak lagi dikembangkan secara aktif — timnya telah bergabung ke Better Auth. Kolom ini ditampilkan sebagai referensi untuk project yang masih menggunakannya.
Rekomendasi: Gunakan Better Auth untuk semua project baru — framework-agnostic, RBAC built-in, Cookie otomatis, dan merupakan ekosistem penerus NextAuth.js. Gunakan Custom JWT jika backend sudah memiliki sistem auth sendiri. Gunakan Clerk hanya untuk prototyping cepat.