Files
supabase/apps/docs/pages/guides/storage/access-control.mdx
T

178 lines
6.3 KiB
Plaintext

import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'storage-access-control',
title: 'Access Control',
description: 'Manage who can access your Supabase Storage files.',
subtitle: 'Manage who can access your Supabase Storage files.',
tocVideo: '4ERX__Y908k',
}
Supabase Storage is designed to work perfectly with [Postgres Row Level Security](/docs/guides/database/postgres/row-level-security) (RLS).
You can use RLS to create [Security Access Policies](https://www.postgresql.org/docs/current/sql-createpolicy.html) that are incredibly powerful and flexible, allowing you to restrict access based on your business needs.
## Policies
Policies are just SQL, and they're easy once you get the hang of them. For example, here is a Policy that allows public access to any files in a bucket called "my_bucket_id".
```sql
create policy "Public Access"
on storage.objects
for select -- Allow read access
to anon, authenticated -- Allow access to anonymous and authenticated users
using ( bucket_id = 'my_bucket_id' ); -- Identify the bucket
```
An easy way to get started would be to create RLS policies for `SELECT`, `INSERT`, `UPDATE`, `DELETE` operations and restrict the policies to meet your security requirements. For example, one can start with the following `INSERT` policy:
```sql
create policy "policy_name"
ON storage.objects
for insert with check (
true
);
```
and modify it to only allow authenticated users to upload assets to a specific bucket by changing it to:
```sql
create policy "policy_name"
on storage.objects for insert to authenticated with check (
-- restrict bucket
bucket_id = 'my_bucket_id'
);
```
## Metadata storage
Supabase Storage stores metadata in the `objects` and `buckets` table in the storage schema.
To allow read access to files, the RLS policy must allow users to `SELECT` the `objects` table and for uploading a new object, the RLS policy must grant users access to `INSERT` into the `objects` table and so on. The mapping between the different API calls and the database permissions required is documented in the [Reference docs](/docs/reference/javascript/storage-createbucket).
## Public and private buckets
Storage buckets are private by default. For private buckets, you can access objects via the [download](/docs/reference/javascript/storage-from-download) method. This corresponds to `/object/auth/` API endpoint. Alternatively, you can create a publicly shareable URL with an expiry date using the [createSignedUrl](/docs/reference/javascript/storage-from-createsignedurl) method which calls the `/object/sign/` API.
For public buckets, you can access the assets directly without a token or an Authorisation header. The [getPublicUrl](/docs/reference/javascript/storage-from-getpublicurl) helper method returns the full public URL for an asset. This calls the `/object/public/` API endpoint internally. While no authorization is required for accessing objects in a public bucket, [proper access control](#policies) is required for other operations like uploading, deleting objects from public buckets as well.
Public buckets also tend to have [better performance](/docs/guides/storage-cdn#public-vs-private-buckets).
The URLs to access storage endpoints are prefixed with <code>/storage/v1</code>. For example, on the hosted Platform they will be:
<code>https://[project_ref].supabase.co/storage/v1/object/public/[id]</code>
You can access the storage API directly with the same endpoint. See the <a href="https://supabase.github.io/storage-api">API docs</a> for a full list of operations available.
## Helper functions
Supabase Storage provides SQL helper functions which you can use in your database queries and RLS policies.
### `storage.filename()`
Returns the name of a file. For example, if your file is stored in `public/subfolder/avatar.png` it would return: `'avatar.png'`
**Usage**
This example demonstrates how you would allow any user to download a file called `favicon.ico`:
```sql
create policy "Allow authenticated uploads"
on storage.objects
for select
to public
using (
storage.filename(name) = 'favicon.ico'
);
```
### `storage.foldername()`
Returns an array path, with all of the subfolders that a file belongs to. For example, if your file is stored in `public/subfolder/avatar.png` it would return: `[ 'public', 'subfolder' ]`
**Usage**
This example demonstrates how you would allow authenticated users to upload files to a folder called `private`:
```sql
create policy "Allow authenticated uploads"
on storage.objects
for insert
to authenticated
with check (
storage.foldername(name)[1] = 'private'
);
```
### `storage.extension()`
Returns the extension of a file. For example, if your file is stored in `public/subfolder/avatar.png` it would return: `'png'`
**Usage**
This example demonstrates how you would allow restrict uploads to only PNG files inside a bucket called `cats`:
```sql
create policy "Only allow PNG uploads"
on storage.objects
for insert
to authenticated
with check (
bucket_id = 'cats' and storage.extension(name) = 'png'
);
```
## Usage
Row Level Security is extremely versatile, since it simply uses SQL to express access rules for your data. You can learn more about RLS in the [Database docs](/docs/guides/database/postgres/row-level-security).
### Allowing public access to a bucket
Allow public access to any files in the "public" bucket:
```sql
create policy "Public Access"
on storage.objects for select
to public
using ( bucket_id = 'public' );
```
### Allowing logged-in access to a bucket
Allow logged-in access to any files in the "restricted" bucket:
```sql
create policy "Restricted Access"
on storage.objects for select
to authenticated
using ( bucket_id = 'restricted' );
```
### Allowing individual access to a file
Allow a user to access their own files:
```sql
create policy "Individual user Access"
on storage.objects for select
to authenticated
using ( auth.uid() = owner );
```
---
{/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
<div className="video-container">
<iframe
src="https://www.youtube-nocookie.com/embed/4ERX__Y908k"
frameBorder="1"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</div>
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page