From 2a8dc75e3d89f590cdc427a1f65273c910508575 Mon Sep 17 00:00:00 2001 From: Lenny Date: Fri, 29 May 2026 05:47:01 -0400 Subject: [PATCH] chore(docs): use more restrictive RLS policies for storage in example projects (#46172) ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? docs update ## What is the current behavior? Storage RLS polices unintentionally allow list access to buckets potentially setting a bad example for people starting a new project. ## What is the new behavior? Use more restrictive RLS polices that only allow the intended operations ## Summary by CodeRabbit * **Documentation** * Updated Supabase Storage access-control policies and examples across docs and starter projects. * Tightened avatar image access rules to require explicit operation checks for public reads. * Clarified guidance and added explanatory comments in migration and README examples to illustrate the updated access patterns. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46172?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) --------- Co-authored-by: Chris Chinchilla --- .../user_management_quickstart_sql_template.mdx | 4 ++-- .../guides/storage/security/access-control.mdx | 13 +++++++++++++ .../interfaces/SQLEditor/SQLEditor.queries.ts | 6 +++--- .../angular-user-management/README.md | 5 +++-- .../user-management/expo-user-management/README.md | 4 +++- .../supabase/migrations/20240403090422_init.sql | 6 +++--- .../nextjs-user-management/README.md | 6 +++--- .../supabase/migrations/20221017024722_init.sql | 6 +++--- .../user-management/solid-user-management/README.md | 4 +++- .../svelte-user-management/README.md | 4 +++- .../supabase/migrations/20240403090422_init.sql | 6 +++--- 11 files changed, 42 insertions(+), 22 deletions(-) diff --git a/apps/docs/content/_partials/user_management_quickstart_sql_template.mdx b/apps/docs/content/_partials/user_management_quickstart_sql_template.mdx index 28f790a6d37..276bdfef8ab 100644 --- a/apps/docs/content/_partials/user_management_quickstart_sql_template.mdx +++ b/apps/docs/content/_partials/user_management_quickstart_sql_template.mdx @@ -49,10 +49,10 @@ create trigger on_auth_user_created insert into storage.buckets (id, name) values ('avatars', 'avatars'); --- Set up access controls for storage. +-- Set up access controls for storage. Allows downloading object with public key -- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects - for select using (bucket_id = 'avatars'); + for select using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with check (bucket_id = 'avatars'); diff --git a/apps/docs/content/guides/storage/security/access-control.mdx b/apps/docs/content/guides/storage/security/access-control.mdx index 909896d1a62..075c5a89dc3 100644 --- a/apps/docs/content/guides/storage/security/access-control.mdx +++ b/apps/docs/content/guides/storage/security/access-control.mdx @@ -85,6 +85,19 @@ to authenticated using ( (select auth.jwt()->>'sub') = owner_id ); ``` +Allow anyone to access objects in the `avatars` bucket via publishable key. The `allow_any_operation()` filter is critical here as without it users would be able to list the bucket contents. + + + +This is not needed for public buckets, as they are already publicly accessible + + + +```sql +create policy "Avatar images are publicly accessible." on storage.objects + for select using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); +``` + --- {/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */} diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.queries.ts b/apps/studio/components/interfaces/SQLEditor/SQLEditor.queries.ts index 775c121953b..2f42bc16365 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.queries.ts +++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.queries.ts @@ -935,10 +935,10 @@ create trigger on_auth_user_created insert into storage.buckets (id, name) values ('avatars', 'avatars'); --- Set up access controls for storage. --- See ${DOCS_URL}/guides/storage#policy-examples for more details. +-- Set up access controls for storage. Allows downloading object with public key +-- See ${DOCS_URL}/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects - for select using (bucket_id = 'avatars'); + for select using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with check (bucket_id = 'avatars'); diff --git a/examples/user-management/angular-user-management/README.md b/examples/user-management/angular-user-management/README.md index 9f900f55c3b..224c97d330b 100644 --- a/examples/user-management/angular-user-management/README.md +++ b/examples/user-management/angular-user-management/README.md @@ -46,9 +46,10 @@ create policy "Users can update own profile." on profiles insert into storage.buckets (id, name) values ('avatars', 'avatars'); --- Set up access controls for storage +-- Set up access controls for storage. Allows downloading object with public key +-- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects - for select using (bucket_id = 'avatars'); + for select using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with check (bucket_id = 'avatars'); diff --git a/examples/user-management/expo-user-management/README.md b/examples/user-management/expo-user-management/README.md index c99d084921a..9add39ff072 100644 --- a/examples/user-management/expo-user-management/README.md +++ b/examples/user-management/expo-user-management/README.md @@ -107,9 +107,11 @@ insert into values ('avatars', 'avatars'); +-- Set up access controls for storage. Allows downloading object with public key +-- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects for select - using (bucket_id = 'avatars'); + using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with diff --git a/examples/user-management/expo-user-management/supabase/migrations/20240403090422_init.sql b/examples/user-management/expo-user-management/supabase/migrations/20240403090422_init.sql index 7c102c555fa..d6af1e53e94 100644 --- a/examples/user-management/expo-user-management/supabase/migrations/20240403090422_init.sql +++ b/examples/user-management/expo-user-management/supabase/migrations/20240403090422_init.sql @@ -41,10 +41,10 @@ create trigger on_auth_user_created insert into storage.buckets (id, name) values ('avatars', 'avatars'); --- Set up access controls for storage. --- See https://supabase.com/docs/guides/storage#policy-examples for more details. +-- Set up access controls for storage. Allows downloading object with public key +-- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects - for select using (bucket_id = 'avatars'); + for select using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with check (bucket_id = 'avatars'); diff --git a/examples/user-management/nextjs-user-management/README.md b/examples/user-management/nextjs-user-management/README.md index 894e1818a38..067ff011a33 100644 --- a/examples/user-management/nextjs-user-management/README.md +++ b/examples/user-management/nextjs-user-management/README.md @@ -186,10 +186,10 @@ create trigger on_auth_user_created insert into storage.buckets (id, name) values ('avatars', 'avatars'); --- Set up access controls for storage. --- See https://supabase.com/docs/guides/storage#policy-examples for more details. +-- Set up access controls for storage. Allows downloading object with public key +-- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects - for select using (bucket_id = 'avatars'); + for select using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with check (bucket_id = 'avatars'); diff --git a/examples/user-management/nextjs-user-management/supabase/migrations/20221017024722_init.sql b/examples/user-management/nextjs-user-management/supabase/migrations/20221017024722_init.sql index 7c102c555fa..d6af1e53e94 100644 --- a/examples/user-management/nextjs-user-management/supabase/migrations/20221017024722_init.sql +++ b/examples/user-management/nextjs-user-management/supabase/migrations/20221017024722_init.sql @@ -41,10 +41,10 @@ create trigger on_auth_user_created insert into storage.buckets (id, name) values ('avatars', 'avatars'); --- Set up access controls for storage. --- See https://supabase.com/docs/guides/storage#policy-examples for more details. +-- Set up access controls for storage. Allows downloading object with public key +-- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects - for select using (bucket_id = 'avatars'); + for select using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with check (bucket_id = 'avatars'); diff --git a/examples/user-management/solid-user-management/README.md b/examples/user-management/solid-user-management/README.md index 0a3e64f206d..46e147af84a 100644 --- a/examples/user-management/solid-user-management/README.md +++ b/examples/user-management/solid-user-management/README.md @@ -116,9 +116,11 @@ insert into values ('avatars', 'avatars'); +-- Set up access controls for storage. Allows downloading object with public key +-- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects for select - using (bucket_id = 'avatars'); + using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with diff --git a/examples/user-management/svelte-user-management/README.md b/examples/user-management/svelte-user-management/README.md index a3e7568de3b..57f71249ce8 100644 --- a/examples/user-management/svelte-user-management/README.md +++ b/examples/user-management/svelte-user-management/README.md @@ -114,9 +114,11 @@ insert into values ('avatars', 'avatars'); +-- Set up access controls for storage. Allows downloading object with public key +-- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects for select - using (bucket_id = 'avatars'); + using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with diff --git a/examples/user-management/swift-user-management/supabase/migrations/20240403090422_init.sql b/examples/user-management/swift-user-management/supabase/migrations/20240403090422_init.sql index 7c102c555fa..d6af1e53e94 100644 --- a/examples/user-management/swift-user-management/supabase/migrations/20240403090422_init.sql +++ b/examples/user-management/swift-user-management/supabase/migrations/20240403090422_init.sql @@ -41,10 +41,10 @@ create trigger on_auth_user_created insert into storage.buckets (id, name) values ('avatars', 'avatars'); --- Set up access controls for storage. --- See https://supabase.com/docs/guides/storage#policy-examples for more details. +-- Set up access controls for storage. Allows downloading object with public key +-- See https://supabase.com/docs/guides/storage/security/access-control#policy-examples for more details. create policy "Avatar images are publicly accessible." on storage.objects - for select using (bucket_id = 'avatars'); + for select using (bucket_id = 'avatars' and storage.allow_any_operation(array['object.get_authenticated_info', 'object.get_authenticated'])); create policy "Anyone can upload an avatar." on storage.objects for insert with check (bucket_id = 'avatars');