📖 Scenario: You are managing a database for a small app where users should only see their own data. To keep data safe, you want to enable Row Level Security (RLS) on a table so that each user can only access their own rows.
🎯 Goal: Enable Row Level Security (RLS) on a table called tasks and create a policy that allows users to select only their own tasks based on their user ID.
📋 What You'll Learn
Create a table called tasks with columns id, user_id, and task_name
Enable Row Level Security (RLS) on the tasks table
Create a policy named Users can select their own tasks that allows users to select rows where user_id matches their authenticated user ID
💡 Why This Matters
🌍 Real World
RLS is used in apps where users must only see or modify their own data, such as task managers, personal finance apps, or social media.
💼 Career
Understanding RLS is important for database security roles and backend developers working with multi-tenant applications.
Progress0 / 4 steps
1
Create the tasks table
Create a table called tasks with columns id as a primary key, user_id as a UUID, and task_name as text.
Supabase
Hint
Use CREATE TABLE with the specified columns and types.
2
Enable Row Level Security on tasks
Enable Row Level Security (RLS) on the tasks table using the command ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;.
Supabase
Hint
Use ALTER TABLE tasks ENABLE ROW LEVEL SECURITY; to turn on RLS.
3
Create a policy to allow users to select their own tasks
Create a policy named Users can select their own tasks on the tasks table that allows SELECT only when user_id = auth.uid().
Supabase
Hint
Use CREATE POLICY with FOR SELECT and USING clause comparing user_id to auth.uid().
4
Test the policy by granting select permission
Grant SELECT permission on the tasks table to the authenticated role using GRANT SELECT ON tasks TO authenticated;.
Supabase
Hint
Use GRANT SELECT ON tasks TO authenticated; to allow authenticated users to select rows.
Practice
(1/5)
1. What does enabling Row Level Security (RLS) on a Supabase table do?
easy
A. It backs up the table data to a secure location.
B. It encrypts the entire table data automatically.
C. It controls which rows a user can access based on their identity.
D. It increases the table's storage capacity.
Solution
Step 1: Understand RLS purpose
RLS restricts access to rows in a table depending on who the user is.
Step 2: Compare options
Only It controls which rows a user can access based on their identity. describes controlling row access by user identity, others describe unrelated features.
Final Answer:
It controls which rows a user can access based on their identity. -> Option C
Quick Check:
RLS = Row access control [OK]
Hint: RLS controls row access by user identity, not encryption or backup [OK]
Common Mistakes:
Confusing RLS with encryption
Thinking RLS backs up data
Assuming RLS increases storage
2. Which SQL command correctly enables Row Level Security on a table named profiles in Supabase?
easy
A. ALTER TABLE profiles SET RLS = TRUE;
B. ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
C. ENABLE RLS ON TABLE profiles;
D. SET ROW LEVEL SECURITY ON profiles;
Solution
Step 1: Recall correct SQL syntax for enabling RLS
The correct command is ALTER TABLE [table_name] ENABLE ROW LEVEL SECURITY;.
Step 2: Match options to syntax
Only ALTER TABLE profiles ENABLE ROW LEVEL SECURITY; matches the exact syntax; others are invalid SQL commands.
Final Answer:
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY; -> Option B
Hint: Use ALTER TABLE ... ENABLE ROW LEVEL SECURITY to enable RLS [OK]
Common Mistakes:
Using SET instead of ENABLE
Wrong command order
Missing ALTER TABLE keyword
3. Given the following policy on table tasks with RLS enabled:
CREATE POLICY "Users can view their tasks" ON tasks FOR SELECT USING (user_id = auth.uid());
What will happen if a user tries to select tasks where user_id is different from their own?
medium
A. They will see only tasks where user_id matches their auth.uid().
B. They will get a syntax error.
C. They will see all tasks regardless of user_id.
D. They will see no tasks at all.
Solution
Step 1: Understand the policy condition
The policy allows SELECT only if user_id = auth.uid(), meaning users see only their own tasks.
Step 2: Predict query result for mismatched user_id
If user_id differs, the condition fails, so those rows are not visible.
Final Answer:
They will see only tasks where user_id matches their auth.uid(). -> Option A
Quick Check:
Policy filters rows by user_id = auth.uid() [OK]
Hint: Policy USING clause filters rows by user identity [OK]
Common Mistakes:
Assuming all rows are visible
Expecting syntax errors from policy
Thinking no rows are visible at all
4. You enabled RLS on the orders table but users report they cannot see any rows even though policies exist. What is the most likely cause?
medium
A. The table has too many rows.
B. The table is missing a primary key.
C. The database connection is lost.
D. RLS is enabled but no policies allow access to rows.
Solution
Step 1: Understand RLS behavior
When RLS is enabled, access depends on policies. Without policies allowing access, no rows are visible.
Step 2: Evaluate other options
Missing primary key, connection loss, or row count do not directly cause no rows to show due to RLS.
Final Answer:
RLS is enabled but no policies allow access to rows. -> Option D
Quick Check:
RLS needs policies to permit row access [OK]
Hint: Enable policies after RLS to allow row access [OK]
Common Mistakes:
Ignoring missing policies
Blaming unrelated database issues
Assuming RLS shows all rows by default
5. You want to allow users to insert rows into the messages table only if the sender_id matches their authenticated user ID. Which policy correctly enforces this with RLS enabled?
hard
A. CREATE POLICY "Allow insert if sender matches" ON messages FOR INSERT WITH CHECK (sender_id = auth.uid());
B. CREATE POLICY "Allow insert" ON messages FOR INSERT USING (sender_id = auth.uid());
C. CREATE POLICY "Allow insert" ON messages FOR SELECT WITH CHECK (sender_id = auth.uid());
D. CREATE POLICY "Allow insert" ON messages FOR UPDATE WITH CHECK (sender_id = auth.uid());
Solution
Step 1: Identify correct policy type for INSERT
For INSERT, WITH CHECK controls if new rows meet the condition.
Step 2: Match condition to sender_id and auth.uid()
The condition sender_id = auth.uid() ensures users insert only their own messages.
Step 3: Verify options
CREATE POLICY "Allow insert if sender matches" ON messages FOR INSERT WITH CHECK (sender_id = auth.uid()); uses FOR INSERT with WITH CHECK and correct condition; others use wrong commands or clauses.
Final Answer:
CREATE POLICY "Allow insert if sender matches" ON messages FOR INSERT WITH CHECK (sender_id = auth.uid()); -> Option A
Quick Check:
INSERT policies use WITH CHECK to validate new rows [OK]
Hint: Use WITH CHECK for INSERT policies to validate new rows [OK]
Common Mistakes:
Using USING instead of WITH CHECK for INSERT
Applying SELECT or UPDATE instead of INSERT
Missing condition on sender_id
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.