The RLS Role Confusion That Leaks Every User’s Data
Using `auth.role()` instead of `auth.uid()` in a Supabase RLS policy makes every logged-in user able to read every other user’s data.
By Contributor · published 5/30/2026
In plain English
Protect your app from data leaks by ensuring users can only see their own information rather than everything in your database. Double-check your security settings to verify that access is based on a user's unique ID instead of just confirming they are logged in.
When AI builders like Lovable or Cursor generate Supabase Row Level Security (RLS) policies, they commonly write the following:
```sql
-- What AI often generates (WRONG)
CREATE POLICY "Users can view data"
ON public.user_data
FOR SELECT
USING (auth.role() = 'authenticated');
```
This policy checks only whether someone is logged in — not whether they own the row. The result: every authenticated user can read every row in the table.
The correct policy checks ownership:
```sql
-- Correct
CREATE POLICY "Users can view their own data"
ON public.user_data
FOR SELECT
USING ((select auth.uid()) = user_id);
```
The difference between `auth.role()` and `auth.uid()` is one function call. `auth.role()` returns `'authenticated'` for any logged-in user. `auth.uid()` returns the UUID of the specific logged-in user, which you can compare against a `user_id` column. Additionally, using `(select auth.uid())` instead of bare `auth.uid()` prevents the function from re-evaluating on every row, improving query performance.
**Diagnostic query** — run this in the Supabase SQL editor to check your policies:
```sql
SELECT schemaname, tablename, policyname, qual
FROM pg_policies
WHERE schemaname = 'public'
ORDER BY tablename;
```
If any `qual` column shows `(auth.role() = 'authenticated'::text)` on a table that holds user-specific data, you have the problem. Fix each table by dropping the broken policy and replacing it with one using `auth.uid() = user_id`.
## Why it matters
A data breach between user accounts does not require a hacker. It requires only a logged-in user who opens the browser developer tools and queries the API directly. The Supabase anon key is public by design — the only defense is correct RLS policies.
## Suggested next action
Open your Supabase SQL editor, run the diagnostic query above, and review every `qual` value on tables storing user data.