How to fix StorageApiError: You are not authorized in Supabase
This error occurs when attempting to access Supabase Storage without proper Row-Level Security (RLS) policies or valid authentication. The fix involves creating appropriate RLS policies on the storage.objects table and ensuring your client sends a valid JWT token.
Quick fix
Fixes StorageApiError: You are not authorized
-- Check bucket privacy setting
SELECT name, public
FROM storage.buckets
WHERE name = 'your-bucket-name';- Verify bucket privacy settings
- Check existing RLS policies on storage.objects
- Create RLS policy for authenticated uploads
- Create RLS policy for reading files
-- Check bucket privacy settingSELECT name, publicFROM storage.bucketsWHERE name = 'your-bucket-name';StorageApiError: You are not authorized
What this error means
When you try to upload, download, or manipulate files in Supabase Storage, the request goes through Row-Level Security (RLS) policies on the `storage.objects` and `storage.buckets` tables. By default, Supabase Storage does not allow any operations without explicit RLS policies that grant permission. The "You are not authorized" error means one of two things is happening: 1. No RLS policy exists that allows your user (or anonymous users) to perform the requested operation 2. You're not authenticated, or your JWT token is invalid/expired, and no policy exists for anonymous access This is a security-by-default feature—Supabase requires you to explicitly define who can access what in your storage buckets. Unlike some storage solutions that default to "open," Supabase defaults to "closed" until you create policies.
Typical symptoms
- Upload operations fail with 'You are not authorized' message
- Download requests return 403 or StorageApiError
- Storage operations work in the Supabase Dashboard but fail in your app
- Error occurs for both authenticated and unauthenticated users
- File operations work with service_role key but fail with anon key
- Private bucket access fails even with valid JWT token
Common causes
- No RLS policies exist on storage.objects table for the requested operation (INSERT, SELECT, UPDATE, DELETE)
- RLS policies exist but don't match your authentication context (wrong user ID, role, or claim)
- JWT token is missing, expired, or invalid when accessing private buckets
- Using the anon key for operations that require authentication
- Bucket privacy settings conflict with your RLS policies
- RLS policy uses auth.uid() but user is not authenticated
- Policy checks a JWT claim that doesn't exist or has the wrong value
- Service role key is being used client-side (security risk, policies bypassed in backend only)
How to fix "StorageApiError: You are not authorized"
First, check whether your bucket is public or private. This affects what RLS policies you need:
-- Check bucket privacy setting
SELECT name, public
FROM storage.buckets
WHERE name = 'your-bucket-name';Public buckets: Anyone can read files if a SELECT policy allows it (no authentication required)
Private buckets: Require authentication and SELECT policy to read files
You can change bucket privacy in the Supabase Dashboard under Storage → Buckets → (bucket) → Settings → Public bucket toggle.
View current policies on the storage.objects table to see what's already configured:
-- View all policies on storage.objects
SELECT schemaname, tablename, policyname, permissive, roles, cmd, qual
FROM pg_policies
WHERE tablename = 'objects' AND schemaname = 'storage';If no policies exist for your bucket, or the operations you need aren't covered, you'll need to create them.
To allow authenticated users to upload files to their own folder:
-- Allow authenticated users to upload files
CREATE POLICY "Users can upload their own files"
ON storage.objects
FOR INSERT
TO authenticated
WITH CHECK (
bucket_id = 'your-bucket-name'
AND auth.uid()::text = (storage.foldername(name))[1]
);This policy allows INSERT operations only when:
- The user is authenticated
- The file is going into a folder matching their user ID
- The bucket is 'your-bucket-name'
For allowing uploads to any path:
CREATE POLICY "Authenticated users can upload"
ON storage.objects
FOR INSERT
TO authenticated
WITH CHECK (bucket_id = 'your-bucket-name');To allow users to read files (download or list):
For public read access:
CREATE POLICY "Public files are readable by anyone"
ON storage.objects
FOR SELECT
TO public
USING (bucket_id = 'your-bucket-name');For authenticated users to read their own files:
CREATE POLICY "Users can read their own files"
ON storage.objects
FOR SELECT
TO authenticated
USING (
bucket_id = 'your-bucket-name'
AND auth.uid()::text = (storage.foldername(name))[1]
);For private buckets with signed URLs:
CREATE POLICY "Authenticated users can read files"
ON storage.objects
FOR SELECT
TO authenticated
USING (bucket_id = 'your-bucket-name');To allow users to update or delete their files:
-- Allow users to update their own files
CREATE POLICY "Users can update their own files"
ON storage.objects
FOR UPDATE
TO authenticated
USING (
bucket_id = 'your-bucket-name'
AND auth.uid()::text = (storage.foldername(name))[1]
)
WITH CHECK (
bucket_id = 'your-bucket-name'
AND auth.uid()::text = (storage.foldername(name))[1]
);
-- Allow users to delete their own files
CREATE POLICY "Users can delete their own files"
ON storage.objects
FOR DELETE
TO authenticated
USING (
bucket_id = 'your-bucket-name'
AND auth.uid()::text = (storage.foldername(name))[1]
);Note: The upsert functionality requires SELECT, INSERT, and UPDATE policies all to be present.
Ensure your client code is sending the authentication token:
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://your-project.supabase.co',
'your-anon-key' // Use anon key, not service_role
)
// Sign in first
const { data: authData, error: authError } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'password'
})
// Now storage operations will include the JWT automatically
const { data, error } = await supabase.storage
.from('your-bucket-name')
.upload('user-folder/file.jpg', file)
if (error) {
console.error('Upload error:', error)
}The Supabase client automatically attaches the JWT to Storage API requests after authentication.
Verify your policies work by testing in the Supabase Dashboard:
1. Go to Storage → Select your bucket
2. Try uploading a file
3. If it works in the Dashboard but not in your app, the issue is likely with your client authentication
Use the SQL Editor to test policies directly:
-- Test if current user can insert
SELECT * FROM storage.objects
WHERE bucket_id = 'your-bucket-name';
-- Check current user context
SELECT auth.uid(), auth.role();Advanced notes
### Using Service Role Key (Backend Only)
The service_role key bypasses ALL RLS policies and should never be exposed to the client. Use it only in server-side code:
// Server-side only (Next.js API route, etc.)
import { createClient } from '@supabase/supabase-js'
const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.SUPABASE_SERVICE_ROLE_KEY, // Server env var
{
auth: {
autoRefreshToken: false,
persistSession: false
}
}
)
// This bypasses RLS entirely
const { data, error } = await supabaseAdmin.storage
.from('bucket')
.upload('path/file.jpg', file)### Custom JWT Claims
If your RLS policies check custom claims:
CREATE POLICY "Users with admin role"
ON storage.objects
FOR SELECT
TO authenticated
USING (
bucket_id = 'admin-files'
AND (auth.jwt() ->> 'user_role') = 'admin'
);Ensure the claim exists in your JWT. You can inspect tokens at [jwt.io](https://jwt.io).
### Bucket-Level Policies
In addition to storage.objects policies, you may need policies on storage.buckets for bucket creation:
CREATE POLICY "Users can create buckets"
ON storage.buckets
FOR INSERT
TO authenticated
WITH CHECK (true);### Testing Policies Locally
When using Supabase locally with Docker:
# Start local Supabase
supabase start
# Apply migrations including RLS policies
supabase db reset### Common Policy Patterns
Allow uploads only to user's folder:
auth.uid()::text = (storage.foldername(name))[1]Allow uploads with specific file extensions:
(storage.extension(name)) IN ('jpg', 'png', 'pdf')Limit file size (requires additional checks in your application):
RLS doesn't support file size checks. Implement this in your application layer.
### Debugging Tips
1. Check the PostgreSQL logs in Supabase Dashboard → Logs → Postgres
2. Use EXPLAIN to see if your policy is being evaluated
3. Temporarily create an overly permissive policy to isolate the issue:
CREATE POLICY "temporary_debug_policy"
ON storage.objects
FOR ALL
TO authenticated
USING (true)
WITH CHECK (true);If this works, your issue is policy logic, not authentication. Remember to delete this policy after debugging.
Frequently asked questions
- What does "StorageApiError: You are not authorized" mean?
- buckets tables. By default, Supabase Storage does not allow any operations without explicit RLS policies that grant permission. The "You are not authorized" error means one of two things is happening: 1.
- How do I fix "StorageApiError: You are not authorized"?
- This error occurs when attempting to access Supabase Storage without proper Row-Level Security (RLS) policies or valid authentication. The fix involves creating appropriate RLS policies on the storage.objects table and ensuring your client sends a valid JWT token.
- What causes "StorageApiError: You are not authorized"?
- No RLS policies exist on storage.objects table for the requested operation (INSERT, SELECT, UPDATE, DELETE) RLS policies exist but don't match your authentication context (wrong user ID, role, or claim) JWT token is missing, expired, or invalid when accessing private buckets
- Is the "StorageApiError: You are not authorized" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚Supabase Official Documentation
- 📖Storage Access Control - Supabase Docs(Official Docs)
- 📖Storage Error Codes - Supabase Docs(Official Docs)
- 📖Row Level Security - Supabase Docs(Official Docs)
- 📖Storage Buckets - Supabase Docs(Official Docs)
- 🐙
- 🐙
- 🐙
- 🐙