📖 Scenario: You are managing a database in Supabase and want to control who can see which rows in a table. This is done using Row Level Security (RLS) policies. You will create a table, enable RLS, add a policy, and then test that the policy works as expected.
🎯 Goal: Create a table called documents with columns for id, owner_id, and content. Enable RLS on the table. Add a policy that allows users to select only their own documents. Finally, write a query that tests this policy by selecting documents for a specific user.
📋 What You'll Learn
Create a table documents with columns id (primary key), owner_id (UUID), and content (text).
Enable Row Level Security (RLS) on the documents table.
Create a policy named select_own_documents that allows users to select rows where owner_id matches their user ID.
Write a SQL query that selects all documents for a user with a specific owner_id.
💡 Why This Matters
🌍 Real World
RLS policies are used in real applications to protect user data by ensuring users can only access their own information in shared tables.
💼 Career
Understanding and testing RLS policies is important for database administrators and backend developers working with secure multi-tenant applications.
Progress0 / 4 steps
1
Create the documents table
Write a SQL statement to create a table called documents with columns: id as a primary key of type uuid, owner_id of type uuid, and content of type text. Use gen_random_uuid() as the default value for id.
Supabase
Hint
Use CREATE TABLE with the specified columns and types. Remember to set id as primary key with a default UUID.
2
Enable Row Level Security (RLS)
Write a SQL statement to enable Row Level Security on the documents table.
Supabase
Hint
Use ALTER TABLE documents ENABLE ROW LEVEL SECURITY; to turn on RLS.
3
Create a policy to allow users to select their own documents
Write a SQL statement to create a policy named select_own_documents on the documents table. This policy should allow SELECT only when the owner_id matches the current user's ID, which is available as auth.uid().
Supabase
Hint
Use CREATE POLICY with FOR SELECT and a USING clause that compares owner_id to auth.uid().
4
Write a query to test the RLS policy
Write a SQL SELECT statement to get all columns from documents where owner_id equals the UUID '123e4567-e89b-12d3-a456-426614174000'. This simulates selecting documents for a specific user.
Supabase
Hint
Use SELECT * FROM documents WHERE owner_id = '123e4567-e89b-12d3-a456-426614174000'; to test the policy.
Practice
(1/5)
1. What is the main purpose of Row Level Security (RLS) policies in Supabase?
easy
A. To encrypt data stored in the database
B. To speed up database queries by indexing rows
C. To backup data automatically every hour
D. To control which rows a user can access or modify in a table
Solution
Step 1: Understand RLS purpose
RLS policies restrict access to rows based on user identity or conditions.
Step 2: Compare options
Only To control which rows a user can access or modify in a table describes controlling access to rows per user, which is the core of RLS.
Final Answer:
To control which rows a user can access or modify in a table -> Option D
Quick Check:
RLS controls row access = A [OK]
Hint: RLS controls data visibility per user, not performance or backups [OK]
Common Mistakes:
Confusing RLS with indexing or encryption
Thinking RLS handles backups
Assuming RLS speeds up queries
2. Which SQL command correctly enables Row Level Security on a table named profiles in Supabase?
easy
A. ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
B. ALTER TABLE profiles SET ROW LEVEL SECURITY ON;
C. ALTER TABLE profiles ENABLE RLS;
D. ALTER TABLE profiles ENABLE ROW_LEVEL_SECURITY;
Solution
Step 1: Recall correct syntax for enabling RLS
The correct SQL command is ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;.
Step 2: Match options with syntax
Only ALTER TABLE profiles ENABLE ROW LEVEL SECURITY; matches the exact syntax supported by Supabase/PostgreSQL.
Final Answer:
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY; -> Option A
Quick Check:
Enable RLS syntax = A [OK]
Hint: Use exact phrase ENABLE ROW LEVEL SECURITY after ALTER TABLE [OK]
Common Mistakes:
Using 'RLS' shorthand incorrectly
Using underscores incorrectly
Using SET instead of ENABLE
3. Given this RLS policy on messages table:
CREATE POLICY "Users can view their messages" ON messages
FOR SELECT USING (user_id = auth.uid());
What will happen if user with auth.uid() = '123' runs SELECT * FROM messages;?
medium
A. They will see all messages regardless of user_id
B. They will see only messages where user_id = '123'
C. They will see no messages because policy blocks all
D. They will get a syntax error
Solution
Step 1: Understand the policy condition
The policy allows SELECT only if user_id = auth.uid(). For user '123', only rows with user_id '123' are visible.
Step 2: Predict query result
The SELECT query returns only messages owned by user '123'. No syntax errors occur.
Final Answer:
They will see only messages where user_id = '123' -> Option B
Quick Check:
Policy filters rows by user_id = auth.uid() = B [OK]
Hint: Policy filters rows by user_id matching auth.uid() [OK]
Common Mistakes:
Assuming all rows are visible
Thinking policy blocks all rows
Confusing syntax error with policy effect
4. You wrote this RLS policy:
CREATE POLICY "Allow updates" ON profiles
FOR UPDATE USING (user_id = auth.uid());
But users report they cannot update their profiles. What is the likely problem?
medium
A. auth.uid() returns NULL causing policy to fail
B. RLS is not enabled on the profiles table
C. The policy should use WITH CHECK instead of USING
D. The policy name is invalid
Solution
Step 1: Understand difference between USING and WITH CHECK
USING controls which rows can be selected or updated; WITH CHECK controls which updated rows are allowed after update.
Step 2: Identify update permission issue
For UPDATE, WITH CHECK is needed to allow the new row values. Using only USING blocks updates even if row is accessible.
Step 3: Check other options
RLS must be enabled, but question implies it is. auth.uid() returning NULL is unlikely if user is logged in. Policy name is valid.
Final Answer:
The policy should use WITH CHECK instead of USING -> Option C
Quick Check:
Update policies need WITH CHECK = A [OK]
Hint: Use WITH CHECK for update permission, not just USING [OK]
Common Mistakes:
Using only USING clause for updates
Forgetting to enable RLS
Assuming policy name affects behavior
5. You want to test if your RLS policy on orders table correctly restricts users to only see their own orders. Which approach is best to verify this?
hard
A. Run SELECT * FROM orders; as different authenticated users and check results
B. Disable RLS temporarily and check if all orders are visible
C. Check the policy text only without running queries
D. Run SELECT * FROM orders; as the database admin user
Solution
Step 1: Understand testing RLS requires simulating user access
Testing RLS means running queries as different users to see if access is limited correctly.
Step 2: Evaluate options
Run SELECT * FROM orders; as different authenticated users and check results runs queries as different users, which tests the policy effectively. Disable RLS temporarily and check if all orders are visible disables RLS, which doesn't test policy. Check the policy text only without running queries only reads policy text, no test. Run SELECT * FROM orders; as the database admin user uses admin user who bypasses RLS.
Final Answer:
Run SELECT * FROM orders; as different authenticated users and check results -> Option A
Quick Check:
Test RLS by querying as different users = D [OK]
Hint: Test RLS by querying as different users, not admin [OK]
Common Mistakes:
Testing only as admin user
Disabling RLS to test policies
Not running actual queries
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.