Secure Supabase Storage: Public Read, Authenticated Write Buckets
Learn how to configure a Supabase Storage bucket that allows anyone to download files while restricting uploads to authenticated users. This guide walks through prerequisites, policy setup, validation, and recovery steps.
27 Jun 2026, 23:05 UTC

Desired Outcome
Set up a Supabase Storage bucket that anyone can read (download) but only authenticated users can write (upload). This is ideal for public asset libraries where the content is freely consumable but additions are controlled.
Prerequisites
- Supabase project with PostgreSQL and Storage enabled.
- Access to the Supabase Dashboard or the
supabaseCLI. - Authenticated client SDK (JavaScript, Python) with a valid JWT.
- Knowledge of Supabase’s bucket policy syntax.
Procedure
- Create a bucket via the dashboard or CLI.
- Set the bucket’s default policy to 'public read'.
- Add a policy rule that grants 'write' permission only to authenticated users (role: authenticated) using the policy editor.
- Deploy the policy.
- Test by uploading a file with an authenticated client and attempting upload with an unauthenticated client to confirm enforcement.
Checks
- Verify the bucket’s policy JSON reflects the intended read/write rules.
- Attempt file upload as an authenticated user—should succeed.
- Attempt upload as an unauthenticated user—should fail with 403.
- Confirm file download works for any user.
- Review server logs for policy enforcement entries.
Verification
To verify the configuration, export the bucket policy JSON via the Supabase dashboard or CLI and confirm the 'write' rule includes only the authenticated role. Use the Supabase client SDK to upload a test file with a valid JWT and verify the file appears in the bucket. Attempt the same upload with an expired or missing JWT and confirm a 403 response. Inspect the bucket's access logs in Supabase to see the policy enforcement decisions. Check the bucket's public URL from a browser to confirm read access works for all users.
Example: Policy Configuration
When defining the policy for authenticated uploads, the JSON structure for the rule should look similar to this:
{
"name": "Allow_authenticated_uploads",
"description": "Allows any logged-in user to upload files",
"target": "public",
"role": "authenticated",
"command": ["INSERT", "UPDATE", "DELETE"],\n "expression": "auth.role() = 'authenticated'"
}Note: The authenticated role applies to any user with a valid session, not just admins.
Recovery Options
- Rollback policy: If the bucket becomes unintentionally public, remove the
public-readflag by resetting the bucket’s default policy. - Re-enable public read: If access is lost accidentally, re-apply the
public-readflag in the bucket settings.
Cautions
Public read policies expose file URLs; avoid storing sensitive data in public buckets. Supabase policy syntax and default roles may change between releases; ensure you reference the correct API version.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.