S
Supabase2w ago
Nari

RLS insert still failing for anon role even with correct policy

I’m trying to submit a booking form from my frontend to a Supabase table bookings with RLS enabled. I’ve created the following policy:
CREATE POLICY "allow_anonymous_insert_bookings"
ON public.bookings
FOR INSERT
TO anon
WITH CHECK (true);
CREATE POLICY "allow_anonymous_insert_bookings"
ON public.bookings
FOR INSERT
TO anon
WITH CHECK (true);
which grants:
GRANT USAGE ON SCHEMA public TO anon;
GRANT INSERT ON public.bookings TO anon;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO anon;
GRANT USAGE ON SCHEMA public TO anon;
GRANT INSERT ON public.bookings TO anon;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO anon;
pg_policies confirms the policy is PERMISSIVE and exists for the anon role, and my call to a debug_auth() function shows:
[ { "current_user": "anon", "role": "anon", "uid": null } ]
[ { "current_user": "anon", "role": "anon", "uid": null } ]
So I KNOW I'm using the anon role. this is what the frontend code to insert looks like:
const { data, error } = await supabase
.from('bookings')
.insert([bookingData]);
const { data, error } = await supabase
.from('bookings')
.insert([bookingData]);
example contents of bookingData (to be submitted:
const bookingData = {
name: "Test User",
email: "test.user@example.com",
phone: "5551234567",
address: "123 Example Street",
services: ["deep_clean"],
add_ons: ["fridge", "window_washing"],
date_time: "2025-09-15T14:30",
special_instructions: "Please focus extra on the kitchen area.",
estimated_price: 325,
status: "pending"
};
const bookingData = {
name: "Test User",
email: "test.user@example.com",
phone: "5551234567",
address: "123 Example Street",
services: ["deep_clean"],
add_ons: ["fridge", "window_washing"],
date_time: "2025-09-15T14:30",
special_instructions: "Please focus extra on the kitchen area.",
estimated_price: 325,
status: "pending"
};
and finally the issue i am facing when trying to submit:
POST https://<project>.supabase.co/rest/v1/bookings?columns=...
401 Unauthorized
"new row violates row-level security policy for table \"bookings\""
POST https://<project>.supabase.co/rest/v1/bookings?columns=...
401 Unauthorized
"new row violates row-level security policy for table \"bookings\""
ANY help would be appreciated. It should be noted that this all works if i disable RLS, but I dont think thats a good idea for many reasons.
19 Replies
garyaustin
garyaustin2w ago
Check the API Gateway log details and see if you are really anon, versus authenticated. And is that your real code for insert? You don't have a .select() on it?
Nari
NariOP2w ago
I did have a select on it, I just removed it for the sake of testing (apparently that might have been a problem as i didnt grant select permissions.) didnt help though.
Nari
NariOP2w ago
as for the logs, here is one such failure message (i dont really know whats sensitive but this is a test anyway
No description
garyaustin
garyaustin2w ago
You are anon. Turn off RLS on the table and see if it works. Then add in a select policy. Any other RLS policies on the table? Permissive is the correct type and your With Check looks fine.
Nari
NariOP2w ago
Turning off RLS does work, I'm able to upload stuff directly to the database (scary) without problems. Going to try the select policy right now select policy i added
CREATE POLICY "allow_anon_select_bookings"
ON public.bookings
FOR SELECT
TO anon
USING (true);
CREATE POLICY "allow_anon_select_bookings"
ON public.bookings
FOR SELECT
TO anon
USING (true);
and... OH it seems to work now! no way that was the only issue...
garyaustin
garyaustin2w ago
Yeah, but it says you have a .single() or .select() on the insert if that is limiting you.
Nari
NariOP2w ago
Well it doesnt seem to be, it seems that adding that select policy was all thats needed because now i have it going cleanly into my database! thank you so so so much for your rapid response my guy, you saved my night you have no idea
garyaustin
garyaustin2w ago
Did you turn back on RLS
Nari
NariOP2w ago
yes!
garyaustin
garyaustin2w ago
Then your code that is running has a .select() in it.
Nari
NariOP2w ago
aye, now it does, I added it back to test it out. perhaps it did before, i changed the insert statement so many times what was shown here was my last resort i may have been running it elsewhere. should anon not have access to select? im sure there are safer ways to set this up, but i think for a public booking form this might be fine
garyaustin
garyaustin2w ago
That is up to how you want to do things. I would not have anon insert or select.
Nari
NariOP2w ago
how would you suggest this be handled? if youve any resources i would gladly read them you have helped quite a bit already!
garyaustin
garyaustin2w ago
So you have a booking form that does not require log in?
Nari
NariOP2w ago
yes
garyaustin
garyaustin2w ago
If so at a minimum don't do the .select() in your client and don't turn on select RLS. With that on anyone can see all the booking table entries.
Nari
NariOP2w ago
oh dear yeah that would be pretty bad...
garyaustin
garyaustin2w ago
You could also consider doing an edge function or rpc call to a postgres function that allows anon users to insert and yet you can still protect the tables. With edge functions you could even rate limit. You could also track IP and only allow one booking per IP with function checks. But this all gets complicated.
Nari
NariOP2w ago
but certainly necessary. I dont feel too comfortable with the current setup if its possible to read all the values publically. This however is a good starting point, I will look into this right now. theres always more to learn... Thanks again for your help! NICE I set up an edge functino that actually seems to work!. deleted all the previous unsafe policies to accomodate it, thank you for the idea!

Did you find this page helpful?