Belajar Zustand - Security & Best Practice State
Episode 15 of 23

Belajar Zustand - Security & Best Practice State

Episode ini membahas keamanan state di Zustand: mengapa token tidak boleh masuk ke store yang ter-persist, cara memilih storage yang aman, dan bagaimana menyusun klasifikasi state. Kalian juga belajar akses kontrol berbasis role di UI dengan otorisasi server sebagai lapisan pengaman utama.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

State management bukan hanya soal performa, tetapi juga keamanan. Episode 15 membahas bagaimana memperlakukan data sensitif di dalam Zustand: mengapa token tidak boleh masuk ke store yang ter-persist, bagaimana memilih storage yang aman, dan bagaimana menyusun klasifikasi state agar aplikasi mudah dipelihara dan diperiksa. Kita juga membahas akses kontrol berbasis role di UI.

Setelah episode ini, kalian tahu cara menaruh state pada tempatnya dan menjaga data sensitif tidak bocor ke penyimpanan yang bisa dibaca siapa pun.

Data Sensitif di Store yang Ter-persist

Bahaya Persist untuk Token

Middleware persist menulis state ke localStorage atau storage lain sebagai teks biasa. Siapa pun yang membuka DevTools bisa membaca nilai tersebut. Menyimpan token akses di store persist sama dengan menempel token di dinding browser.

Token sebaiknya disimpan di cookie httpOnly yang dikelola server, atau di memory store tanpa persist. Jika token harus hidup di Zustand untuk request, buat store terpisah tanpa persist:

JSMemory store tanpa persist
import { create } from 'zustand'
 
interface TokenState {
  token: string | null
  setToken: (token: string) => void
  clearToken: () => void
}
 
export const useTokenStore = create<TokenState>()((set) => ({
  token: null,
  setToken: (token) => set({ token }),
  clearToken: () => set({ token: null }),
}))

Store useTokenStore tanpa middleware persist hanya menyimpan token di memori. Saat tab ditutup, token hilang — persis yang diinginkan untuk data sesi yang sensitif.

Memilih Storage Aman dan Sanitasi Data

Ketika persist tetap diperlukan, batasi data yang tersimpan dengan partialize agar hanya field aman yang ikut. Jangan pernah menyimpan secret atau PII penuh ke storage:

JSpartialize membatasi data yang dipersist
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
 
export const useUserStore = create<UserState>()(
  persist(
    (set) => ({
      id: null,
      email: '',
      role: 'guest',
      token: null,
      setSession: (data) => set(data),
    }),
    {
      name: 'user-prefs',
      partialize: (state) => ({
        email: state.email,
        role: state.role,
      }),
    },
  ),
)

partialize: (state) => ({ email, role }) memastikan hanya email dan role yang tersimpan, sementara token tetap berada di memori. Ini bentuk sanitasi minimal: pisahkan field sensitif dan non-sensitif dengan eksplisit.

Klasifikasi State

State aplikasi layak diklasifikasikan sebelum memilih tempat menyimpannya:

  • UI state: modal, dropdown, form — local state atau Zustand tanpa persist.
  • Global state: sesi, preferensi, theme — Zustand dengan persist bila perlu.
  • Server state: data API — TanStack Query, bukan Zustand.
  • URL state: filter, pagination, query params — library seperti nuqs, agar link bisa di-share.

Klasifikasi ini menjawab pertanyaan "state ini harus hidup di mana" tanpa berdebat ulang setiap fitur baru.

Single Responsibility dan Akses Berbasis Role

Satu Store Satu Tanggung Jawab

Store yang menampung segala hal menjadi sulit diuji dan diprediksi. Buat satu store per domain: useAuthStore, useCartStore, useUiStore. Saat store mulai mengurus dua hal yang tidak saling terkait, pecah menjadi slice atau store baru.

Akses Berbasis Role di UI

Role dan permission menentukan apa yang boleh dilihat pengguna. Simpan role di store, lalu jaga UI agar hanya merender elemen yang diizinkan:

JSGuard akses berbasis role
const role = useAuthStore((s) => s.user?.role)
 
function AdminButton() {
  if (role !== 'admin') {
    return null
  }
  return <button onClick={() => handleDelete()}>Hapus</button>
}

if (role !== 'admin') adalah lapisan UI, bukan pengaman utama. Validasi tetap wajib di server — akses kontrol UI hanya menyembunyikan, bukan mengamankan. Selalu dua lapis: frontend untuk UX, backend untuk otorisasi.

Penutup

Episode 15 membahas keamanan state: tidak menyimpan token di store persist, membatasi data dengan partialize, memilih storage yang aman, mengklasifikasikan state, dan menerapkan akses berbasis role di UI dengan otorisasi server sebagai fondasi.

Inti yang harus dibawa pulang:

  • localStorage adalah storage publik yang bisa dibaca lewat DevTools.
  • Token sebaiknya di cookie httpOnly atau memory store tanpa persist.
  • partialize membatasi field yang ikut tersimpan.
  • Klasifikasikan state: UI, global, server, dan URL.
  • Satu store untuk satu tanggung jawab domain.
  • Role di UI hanya UX; otorisasi sejati ada di server.

Di episode 16 selanjutnya kita akan membahas custom middleware dan slice pattern — menulis middleware sendiri sebagai wrapper, memakai logging dan tracking, memecah store besar menjadi slices, dan mengetik slices agar bisa saling mengakses.

Belajar Zustand - Security & Best Practice State | Belajar Zustand