dev-resources.site
for different kinds of informations.
Auth in Supabase storage
Authentication and Authorization
Now we will go through the authentication and authorization lifecycle. How authorization and authentication work in the storage repository. We will understand the various parts involved in authentication and authorization and how they work together.
Authentication and Authorization Components
The Supabase storage repository employs a combination of JWTs (JSON Web Tokens) and row-level security (RLS) policies to ensure that only authorized users and services can access resources. It uses JWT for authentication and RLS for authorization. Here's a step-by-step breakdown:
- Authentication:
- JWT Acquisition: Clients obtain JWTs through the Supabase Auth service or through the storage service for a signed upload. These JWTs contain claims that specify the user's identity, roles, and permissions. With these JWTs, the client can access the storage service. Sometimes, when signed URLs are generated by the storage service, the JWT also contains the resource to which it has access.
-
Request Headers: Clients making requests to the Storage API include the JWT in the
Authorization
header, typically using theBearer <token>
format (or via query params for upload signed URLs). -
JWT Extraction (HTTP Layer):
* Theauth-jwt
plugin extracts the JWT from the request'sAuthorization
header or query param.
* It removes theBearer
prefix if present.
* The extracted JWT is stored inrequest.jwt
.-
JWT Verification (Internal Layer):
- The
verifyJWT
function fromsrc/internal/auth/jwt.ts
is called. - It uses the server's JWT secret or JWKS to verify the signature and validity of the JWT.
- If signature validation fails, a 401 error is returned.
- The
-
Retrieving the Key for Signature Verification:
- The function
getJWTVerificationKey
determines which key to use for verification based on thekid
on the token or the static secret. - If the alg header from the token is using RSA or ECC, the key will be determined using
kty
andkid
, or the static secret will be returned. - If there is an issue while extracting the public key from JWKS, the system will fall back to use the configured static key if the algorithm is HS256 or fail.
- The function
-
JWT Payload Parsing: If the JWT is valid, the payload is parsed and saved in
request.jwtPayload
. Therole
key is assigned torequest.jwtPayload.role
if available. -
Request Decoration: If the JWT is valid, the system also sets
request.isAuthenticated
totrue
.- If an invalid or no JWT is provided but the route has the
allowInvalidJwt
option,request.jwtPayload
andrequest.isAuthenticated
are set toanon
andfalse
, respectively.
- If an invalid or no JWT is provided but the route has the
- Authorization Through RLS: The RLS will check the authorization on specific database queries as explained in the next section.
-
JWT Verification (Internal Layer):
- Authorization and Row Level Security (RLS):
-
Database Queries: When performing database operations (reading, creating, updating, deleting records), queries go through RLS policies.
-
RLS Policies:
- RLS policies are defined in the database using PostgreSQL's row-level security mechanism. These policies are configured by using the
storage.install_roles
flag; the roles that you set when running the migrations are set on the database as well. - RLS policies define rules for which users can access which rows of the database. These policies are based on the context of the request, such as
auth.uid()
(user ID) andauth.role()
(user role) claims inside a JWT. - For example, a simple policy can be written as
USING(owner = auth.uid())
, which means only the objects with the sameowner
can be viewed, modified, or deleted.
- RLS policies are defined in the database using PostgreSQL's row-level security mechanism. These policies are configured by using the
- Dynamic RLS: The system will extract the current authenticated user information from the JWT token and add it to the current database context. The RLS policy will then use these values to validate the user permissions against the database.
- Enforcement: The database automatically applies the RLS policies on queries and operations to restrict data access.
-
Error Handling: If an RLS policy violation occurs, PostgreSQL returns an error. The application catches this error using the
DatabaseError
error handler and returns a 403 (Unauthorized) response. - Bypass with Service Key: For server operations, the system uses the service key that is generated and passed on the JWT token; this can be used to bypass any RLS rules in the database.
-
Scope Setting: Before each database query, using the
TenantConnection.setScope
, the system sets the required options to thecurrent_setting
, allowing RLS to extract the required information from it. -
Tracing: If tracing is enabled, a span named
knex.query
is created using the@opentelemetry/instrumentation-knex
, which shows the database query that was performed.
-
RLS Policies:
-
Presigned S3 URLs
- The presigned S3 URL follows the same flow as a normal GET object request.
- The URL is signed on the server side to allow access to the protected resources; it is used when uploading files or accessing private files using the S3 protocol.
-
signJWT
is used to sign the URL using the server secrets.
-
- The authentication process happens using the
x-signature
header, which has the value of the signed JWT.- The
verifyObjectSignature
will verify if the provided token is valid using theverifyJWT
function, and the function will check if the URL on the JWT matches the route.
- The
-
Admin API Key:
- Any request to the
/admin
routes needs to send anapikey
in the header to pass the validation; if this header is missing or invalid, the request will be refused.
- Any request to the
Role of Schemas in Validation
JSON Schemas are used here to validate the request and response data.
- Request Validation:
-
Definition: JSON Schema is used to define the structure and data types of incoming HTTP requests (both params, body, and headers).
-
Enforcement: Fastify uses the
ajv
library to validate all incoming HTTP requests against the defined schemas before the route handler is called. - Error Handling: If a request doesn't conform to the schema, Fastify automatically returns a 400 error with information about the validation failure.
-
Enforcement: Fastify uses the
-
Data Structure:
-
Data Definition: Schemas also help define the properties of the returned objects, which are later used to define interfaces using the
json-schema-to-ts
library such asObj
,Bucket
,UploadMetadata
, and more.
-
Data Definition: Schemas also help define the properties of the returned objects, which are later used to define interfaces using the
-
Metadata Validation:
- User metadata is validated as a generic
JSONB
, so it doesn't have specific validation of its content to avoid having schema errors during the upload, as the content can be anything.
- User metadata is validated as a generic
How a request is authenticated and authorized
- Client Request: A client attempts to upload a file, create a bucket, download an object, or any other action.
- JWT Verification: The server verifies the client's JWT, extracting authentication information.
- Schema Validation: The server validates the client's request payload against the API schemas.
- Database Interaction: If authentication and validation are successful, a database transaction is created, and the data is sent to the database.
- RLS Enforcement: The database applies row-level security policies using data extracted from the JWT, restricting access to resources.
- Operation Execution: If authorization is successful, then the operation is executed.
- Response Generation: The system returns a response after completing all validation, auth, and permission steps.
Benefits
- Improved Data Integrity: Schemas enforce consistency and correctness of input data, preventing invalid data from entering the system.
- Declarative Approach: Using schemas in code makes it easier to see what the expected parameters are for every API call.
- Developer Experience: The process provides a better developer experience by adding type safety and auto-validation features.
- Extensible: Since the system only works on two levels—one is JWT and the other is RLS—any system that uses JWT and RLS can be used with the storage repository. So, you only need JWT and Postgres to use the storage repository.
This ends our exploration of the auth/authentication, RLS, and schema workflow. You should now have a clear view of how those pieces play an important role in every request, making the Supabase Storage Engine a reliable and secure system. Let me know if you have more questions or if you want to explore any topic in more detail.
Featured ones: