Supabase: new row violates row-level security policy for table
Cómo solucionar el error de Row Level Security (RLS) en Supabase. Configurar políticas RLS correctamente para INSERT, SELECT, UPDATE y DELETE.
¿Por qué ocurre?
Supabase bloquea la operación porque: - La tabla tiene Row Level Security (RLS) activado pero no hay políticas que permitan la operación - La política existe pero no aplica al usuario actual (anon vs authenticated) - Falta la cláusula `auth.uid() = user_id` en la política - Estás usando la clave `anon` (pública) para insertar en una tabla que solo permite usuarios autenticados - La política de INSERT no coincide con la de SELECT (dos políticas separadas)
Solución paso a paso
1. Diagnóstico: ver las políticas actuales
-- En Supabase SQL Editor
SELECT schemaname, tablename, policyname, cmd, qual, with_check
FROM pg_policies
WHERE tablename = 'tu_tabla';
2. Política básica para usuarios autenticados
-- Permitir que cada usuario vea solo sus propios datos
CREATE POLICY "users_select_own" ON public.posts
FOR SELECT
USING (auth.uid() = user_id);-- Permitir que usuarios autenticados inserten sus propios datos
CREATE POLICY "users_insert_own" ON public.posts
FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Permitir actualizar solo sus propios datos
CREATE POLICY "users_update_own" ON public.posts
FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
-- Permitir borrar solo sus propios datos
CREATE POLICY "users_delete_own" ON public.posts
FOR DELETE
USING (auth.uid() = user_id);
3. Política para contenido público (lectura sin auth)
-- Cualquiera puede leer posts publicados
CREATE POLICY "public_read_published" ON public.posts
FOR SELECT
USING (published = true);-- Solo autenticados pueden crear
CREATE POLICY "auth_insert" ON public.posts
FOR INSERT
TO authenticated
WITH CHECK (true);
4. Usar service_role key para operaciones admin (bypass RLS)
// ⚠️ Solo en el servidor, nunca en el cliente
import { createClient } from '@supabase/supabase-js'const supabaseAdmin = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_SERVICE_ROLE_KEY // ← bypasea RLS
)
// En una API route / server action
const { data, error } = await supabaseAdmin
.from('posts')
.insert({ title: 'Admin post', user_id: userId })
5. Desactivar RLS temporalmente (solo para desarrollo)
-- ⚠️ SOLO en desarrollo/testing
ALTER TABLE public.posts DISABLE ROW LEVEL SECURITY;-- Reactivar
ALTER TABLE public.posts ENABLE ROW LEVEL SECURITY;
6. Verificar usuario autenticado en el cliente
const { data: { user } } = await supabase.auth.getUser()
console.log('Usuario:', user?.id) // null si no está autenticado// Asegurarse de incluir el token en las requests
const supabase = createClient(url, anonKey, {
auth: {
persistSession: true,
autoRefreshToken: true,
}
})
Cómo evitarlo en el futuro
- Activa RLS en TODAS las tablas desde el principio, no como afterthought - En Supabase Dashboard hay un "RLS Advisor" que sugiere políticas automáticamente - Nunca uses la `service_role` key en código de cliente (frontend) - Prueba las políticas con la función `auth.uid()` en el SQL Editor con distintos usuarios - El "Policy Tester" de Supabase Dashboard permite simular operaciones como distintos usuarios
¿Quieres que una IA te ayude? Genera el prompt perfecto para tu error:
Generador de Prompts