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.

AspekCookie (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
CSRFPerlu flag SameSite=Lax atau StrictKebal (tidak auto-terkirim)
Token dikirim ke APIOtomatis oleh browser (withCredentials)Manual — harus diambil & diset di header
PenggunaanToken autentikasi sesiUI 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: Bearer header

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>
  );
}
✅ KelebihanFramework-agnostic (Next.js & Vite), HttpOnly Cookie otomatis, TypeScript-first, built-in RBAC & session management, tidak perlu server khusus
❌ KekuranganLibrary 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!,
    }),
  ],
});
✅ KelebihanKomunitas besar, 40+ OAuth provider built-in, banyak referensi & tutorial tersedia
❌ KekuranganTidak 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);
  },
);
✅ KelebihanKontrol penuh atas alur token, tidak ada dependency eksternal, fleksibel untuk backend apapun
❌ KekuranganHarus 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>
  );
}
✅ KelebihanSetup tercepat (hitungan menit), UI komponen siap pakai, multi-factor auth & social login built-in, managed sepenuhnya
❌ KekuranganBerbayar 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

KriteriaBetter Auth ⭐NextAuth.js (Legacy)Custom JWTClerk
Bekerja di Next.js✅✅✅✅
Bekerja di Vite (React)✅❌✅✅
HttpOnly Cookie otomatis✅✅Manual✅
RBAC built-in✅❌ ManualManual✅
OAuth (Google, GitHub, dll)✅✅ TerbaikManual✅
Refresh token otomatis✅✅Manual✅
Aktif dikembangkan✅❌ Tidak lagi✅✅
Data user di server sendiri✅✅✅❌
Gratis tanpa batas✅✅✅⚠️
Kompleksitas setupRendahSedangTinggiSangat 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.

© 2026 Bit Group Asia. All rights reserved.

ArchitectureSecurityGuidelines