patterntypescriptCritical
Supabase Auth Setup with Row Level Security
Viewed 0 times
Supabase JS v2
supabaserlsrow level securityauth.uidservice roleanon keypostgresql policy
Error Messages
Problem
Supabase exposes a public API key in client-side code. Without Row Level Security policies, any authenticated user can read or modify other users' data directly through the Supabase client.
Solution
Enable RLS on every table. Write policies that use auth.uid() to scope reads and writes to the owning user. Use the server-side supabaseAdmin client (service role key) only in trusted server environments, never in the browser.
Why
The anon and authenticated Supabase roles are enforced at the PostgreSQL level through RLS. Policies run inside the database engine — they cannot be bypassed by client-side manipulation.
Gotchas
- Enabling RLS on a table with no policies blocks all access including your own — add a policy before enabling in production
- The service role key bypasses RLS entirely — never expose it client-side or commit it to version control
- auth.uid() returns null for unauthenticated requests; policies that don't handle null will either block everything or allow everything
Code Snippets
RLS policies for a user-owned posts table
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- Users can only read their own posts
CREATE POLICY "select_own_posts" ON posts
FOR SELECT USING (auth.uid() = user_id);
-- Users can only insert rows they own
CREATE POLICY "insert_own_posts" ON posts
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- Users can only update their own posts
CREATE POLICY "update_own_posts" ON posts
FOR UPDATE USING (auth.uid() = user_id);Server-only Supabase admin client
import { createClient } from '@supabase/supabase-js';
// Only import this in server-side code (API routes, Server Actions)
export const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!, // Never expose this client-side
);Revisions (0)
No revisions yet.