Supabase RLS untuk CMS: Aman Tanpa Ribet
Backend10 min read

Supabase RLS untuk CMS: Aman Tanpa Ribet

Setup Row Level Security di Supabase buat CMS blog. Publik cuma bisa baca artikel published, admin write lewat server route. Gampang kok implementasinya.

DaunsCode Editorial Team

admin@daunscode.com • 12 Feb 2026

Kenapa RLS Itu Penting Banget?

Jadi gini, kalau kamu bikin CMS pake Supabase dan nggak setup RLS (Row Level Security), itu sama aja kayak bikin rumah tapi nggak pasang kunci pintu. Siapa aja yang tau URL API kamu bisa seenaknya baca, edit, bahkan hapus data.

Mungkin kamu mikir "ah kan cuma blog, emang siapa yang mau iseng?" Nah justru itu mindset yang bahaya. Bot scanner itu jalan 24/7 nyari API yang vulnerable. Sekali ketemu, data kamu bisa diobrak abrik.

Apa Itu Row Level Security?

RLS itu fitur dari PostgreSQL (yang dipake Supabase) yang memungkinkan kamu bikin rules di level baris data. Jadi kamu bisa tentuin:

  • Siapa yang boleh baca baris mana
  • Siapa yang boleh insert, update, atau delete baris mana

Bedanya sama permission biasa, RLS itu granular banget. Bukan cuma "user ini boleh akses tabel ini", tapi "user ini boleh akses baris yang memenuhi kondisi tertentu".

Setup RLS untuk Blog CMS

Oke langsung ke prakteknya. Skenario kita:

  • Pengunjung (anon) cuma boleh baca artikel yang statusnya published
  • Admin boleh CRUD semua artikel tapi lewat server route (pake service_role key)
  • User biasa (authenticated) nggak boleh nulis apa apa

Step 1: Enable RLS

Pertama aktifin dulu RLS di tabel articles:

ALTER TABLE public.articles ENABLE ROW LEVEL SECURITY;

Begitu RLS aktif, secara default SEMUA akses di block. Jadi kamu harus bikin policy buat allow akses yang diizinin.

Step 2: Policy Baca Artikel Published

CREATE POLICY "Public can read published articles"
ON public.articles
FOR SELECT
USING (status = 'published');

Policy ini ngizinin siapa aja (termasuk anon) buat baca artikel yang statusnya published. Artikel draft? Nggak keliatan sama sekali.

Step 3: Block Semua Write Operation

CREATE POLICY "Block all inserts"
ON public.articles
AS RESTRICTIVE
FOR INSERT
WITH CHECK (false);

CREATE POLICY "Block all updates"
ON public.articles
AS RESTRICTIVE
FOR UPDATE
USING (false);

CREATE POLICY "Block all deletes"
ON public.articles
AS RESTRICTIVE
FOR DELETE
USING (false);

Keyword RESTRICTIVE itu penting banget. Artinya policy ini HARUS terpenuhi selain policy PERMISSIVE lainnya. Jadi meskipun ada policy lain yang ngizinin, kalau RESTRICTIVE bilang nggak boleh ya tetep nggak boleh.

Step 4: Admin Lewat Service Role

Terus gimana admin bisa nulis? Jawabannya pake service_role key. Key ini bypass RLS secara otomatis. Jadi kamu bikin API route di server (misalnya Next.js API route) yang pake service_role key buat operasi write.

// app/api/admin/articles/route.ts
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY! // bypass RLS
);

export async function POST(req: Request) {
  // validasi auth admin di sini
  const body = await req.json();
  const { data, error } = await supabase
    .from("articles")
    .insert(body)
    .select();
  return Response.json({ data, error });
}

PENTING: service_role key itu JANGAN PERNAH di expose ke client. Simpan di environment variable server side aja.

Testing RLS

Setelah setup, kamu harus tes buat mastiin semuanya bener:

Tes Baca (harusnya berhasil)

Pakai anon key buat fetch artikel published. Harusnya return list artikel yang statusnya published.

Tes Insert (harusnya gagal)

Coba insert pakai anon key. Harusnya return error 42501 (permission denied). Kalau berhasil insert, berarti RLS kamu salah setup.

Tes Baca Draft (harusnya kosong)

Coba fetch artikel draft pakai anon key. Harusnya return array kosong meskipun ada artikel draft di database.

Common Mistakes

Beberapa kesalahan yang sering terjadi:

  1. Lupa enable RLS baru bikin policy tapi lupa aktifin RLS di tabelnya. Policy nggak ngefek kalau RLS belum enabled.

  2. Pakai PERMISSIVE buat block PERMISSIVE itu additive, jadi kalau ada satu aja yang allow ya tetep allowed. Buat block harus pakai RESTRICTIVE.

  3. Service role key di client ini fatal. Kalau service_role key bocor, orang bisa bypass semua RLS kamu.

  4. Nggak tes bikin policy trus langsung deploy tanpa tes. Minimal tes pakai curl dulu.

  5. Terlalu banyak policy policy yang numpuk bikin debugging susah. Keep it simple dan clear.

Best Practices

Beberapa best practices yang kita terapin:

  • Selalu enable RLS di semua tabel yang ada di public schema
  • Pakai RESTRICTIVE policy buat block operation yang sensitif
  • Service role key cuma di server side, titik
  • Tes setiap policy pakai curl atau Supabase SQL editor
  • Dokumentasiin policy kamu biar tim lain ngerti
  • Review policy secara berkala, apalagi kalau ada perubahan requirement

Kesimpulan

RLS itu fitur yang powerful banget buat ngamanin data di Supabase. Dengan setup yang bener, kamu bisa bikin CMS yang aman tanpa perlu bikin backend terpisah yang kompleks.

Kuncinya: enable RLS, bikin policy yang jelas, admin lewat service_role di server, dan selalu tes. Gitu aja sih, nggak ribet kan?

Ready to build the next big thing?

DaunsCode siap bantu arsitektur, UI, dan implementasi produk digital yang scalable untuk bisnis kamu.

Let's Talk Project
SupabaseRLSSecurity
← Kembali ke listing artikel
ContactBlogPortfolioHome