Supabase RLS Policy Generator
To generate comprehensive Row-Level Security policies for Supabase databases, follow these steps systematically.
Step 1: Analyze Current Schema
Before generating policies:
- •Ask user for the database schema file path or table names
- •Read the schema to understand table structures, foreign keys, and relationships
- •Identify tables that need RLS protection
- •Determine the security model: multi-tenant, role-based, or hybrid
Step 2: Identify Security Requirements
Determine access patterns by asking:
- •Is this a multi-tenant application? (tenant_id isolation)
- •What roles exist in the system? (admin, user, viewer, etc.)
- •Are there public vs private resources?
- •Do users need to share resources across accounts?
- •Are there hierarchical permissions? (organization > team > user)
Consult references/rls-patterns.md for common security patterns.
Step 3: Generate RLS Policies
For each table requiring protection, generate policies following this structure:
Enable RLS
ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;
Policy Types to Generate
SELECT Policies - Control read access:
- •User can view their own records
- •User can view records in their tenant
- •Role-based viewing (admins see all)
- •Public records accessible to all authenticated users
INSERT Policies - Control creation:
- •User can create records with their own user_id
- •User can create records in their tenant
- •Role-based creation restrictions
UPDATE Policies - Control modifications:
- •User can update their own records
- •Admins can update all records
- •Tenant-scoped updates
DELETE Policies - Control deletion:
- •User can delete their own records
- •Admin-only deletion
- •Tenant-scoped deletion
Policy Templates
Use templates from assets/policy-templates.sql:
Basic User Ownership:
CREATE POLICY "Users can view own records" ON table_name FOR SELECT USING (auth.uid() = user_id);
Multi-Tenant Isolation:
CREATE POLICY "Tenant isolation"
ON table_name FOR ALL
USING (
tenant_id IN (
SELECT tenant_id FROM user_tenants
WHERE user_id = auth.uid()
)
);
Role-Based Access:
CREATE POLICY "Admins have full access"
ON table_name FOR ALL
USING (
auth.jwt() ->> 'role' = 'admin'
);
JWT Claims:
CREATE POLICY "Organization access"
ON table_name FOR SELECT
USING (
organization_id = (auth.jwt() -> 'app_metadata' ->> 'organization_id')::uuid
);
Step 4: Generate Helper Functions
Create PostgreSQL functions to support complex policies:
-- Function to check user role
CREATE OR REPLACE FUNCTION auth.user_has_role(required_role TEXT)
RETURNS BOOLEAN AS $$
BEGIN
RETURN (auth.jwt() ->> 'role') = required_role;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Function to check tenant membership
CREATE OR REPLACE FUNCTION auth.user_in_tenant(target_tenant_id UUID)
RETURNS BOOLEAN AS $$
BEGIN
RETURN EXISTS (
SELECT 1 FROM user_tenants
WHERE user_id = auth.uid()
AND tenant_id = target_tenant_id
);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
Step 5: Generate Testing Queries
Create test queries to verify policies work correctly:
-- Test as authenticated user SET request.jwt.claim.sub = 'user-uuid'; SELECT * FROM table_name; -- Should see only accessible records -- Test as admin SET request.jwt.claim.role = 'admin'; SELECT * FROM table_name; -- Should see all records -- Test as different tenant SET request.jwt.claim.sub = 'other-user-uuid'; SELECT * FROM table_name; -- Should see different tenant's records
Step 6: Create Migration File
Generate a migration file with proper structure:
-- Migration: Add RLS policies -- Created: [timestamp] -- Enable RLS on tables ALTER TABLE users ENABLE ROW LEVEL SECURITY; ALTER TABLE items ENABLE ROW LEVEL SECURITY; -- Drop existing policies if any DROP POLICY IF EXISTS "policy_name" ON table_name; -- Create new policies [Generated policies here] -- Create helper functions [Generated functions here] -- Grant necessary permissions GRANT SELECT, INSERT, UPDATE, DELETE ON table_name TO authenticated; GRANT SELECT ON table_name TO anon; -- If public read needed
Step 7: Document Generated Policies
Create documentation explaining:
- •What each policy does
- •Which users/roles have what access
- •Any special cases or exceptions
- •How to test the policies
- •Common troubleshooting tips
Use template from assets/policy-documentation-template.md.
Implementation Guidelines
Security Best Practices
- •Always enable RLS on tables with user data
- •Use auth.uid() for user-owned records
- •Use JWT claims for role-based access
- •Prefer SECURITY DEFINER functions for complex logic
- •Test policies with different user roles
- •Use USING clause for read access, WITH CHECK for write validation
Performance Considerations
- •Add indexes on columns used in policies (user_id, tenant_id, role)
- •Keep policy logic simple for better performance
- •Use helper functions for reusable complex logic
- •Avoid subqueries in policies when possible
Common Patterns
Consult references/rls-patterns.md for detailed examples of:
- •Multi-tenant isolation
- •Role-based access control (RBAC)
- •Attribute-based access control (ABAC)
- •Hierarchical permissions
- •Public/private resource splitting
- •Shared resource access
Output Format
Generate files in the following structure:
migrations/ [timestamp]_add_rls_policies.sql docs/ rls-policies.md (documentation) tests/ rls_tests.sql (test queries)
Verification Checklist
Before completing:
- • RLS enabled on all sensitive tables
- • Policies cover all operations (SELECT, INSERT, UPDATE, DELETE)
- • Policies tested with different user roles
- • Indexes added for policy columns
- • Helper functions created for complex logic
- • Documentation generated
- • Test queries provided
- • No policies accidentally grant excessive access
Consulting References
Throughout generation:
- •Consult
references/rls-patterns.mdfor security patterns - •Consult
references/supabase-auth.mdfor auth.uid() and JWT structure - •Use templates from
assets/policy-templates.sql
Completion
When finished:
- •Display the generated migration file
- •Summarize the policies created
- •Provide testing instructions
- •Offer to generate additional policies or modify existing ones