Skip to main content

Access Rules

Beta

This feature is in beta. Core behavior is stable and ready to try, but some APIs or configuration may still evolve before general availability.

Define who can upload, download, and delete files in your storage buckets. Rules are TypeScript functions declared in edgebase.config.ts that return true (allow) or false (deny).

Rules are evaluated on every Client SDK request — Admin SDK and App Functions bypass rules entirely.

That storage bypass applies to all Admin SDKs.

Quick Start​

// edgebase.config.ts
export default defineConfig({
storage: {
buckets: {
photos: {
access: {
read(auth, file) {
return true
},
write(auth, file) {
return auth !== null
},
delete(auth, file) {
return auth !== null && auth.id === file.uploadedBy
},
},
},
},
},
});

Each rule function receives auth (the current user) and file (file metadata), and returns a boolean.

Default Policy​

RuleResult
No access rules definedAll operations denied (403)
Returns trueAllow
Returns falseDeny
Development Mode

When release: false (the default), operations on configured buckets are allowed even without rules — so you can start building immediately. Set release: true before production deployment to enforce deny-by-default.


Examples​

Public bucket — anyone can read, authenticated users upload​

avatars: {
access: {
read(auth, file) {
return true
},
write(auth, file) {
return auth !== null
},
delete(auth, file) {
return auth !== null && auth.id === file.uploadedBy
},
},
},

Private bucket — owner only​

documents: {
access: {
read(auth, file) {
return auth !== null && auth.id === file.uploadedBy
},
write(auth, file) {
return auth !== null
},
delete(auth, file) {
return auth !== null && auth.id === file.uploadedBy
},
},
},

Admin-managed bucket — admins can delete, users can upload​

uploads: {
access: {
read(auth, file) {
return true
},
write(auth, file) {
return auth !== null
},
delete(auth, file) {
return auth !== null && auth.role === 'admin'
},
},
},

Size-restricted uploads​

attachments: {
access: {
read(auth, file) {
return auth !== null
},
write(auth, file) {
return auth !== null && file.size <= 10 * 1024 * 1024 // 10 MB max
},
delete(auth, file) {
return auth !== null && auth.id === file.uploadedBy
},
},
},

Reference​

Operations​

OperationWhenfile argument?
readDownload, get metadataYes
readList filesNo — file is {} (empty object)
writeUpload (single or multipart), update metadataYes
deleteDelete a fileYes
file argument availability

For list operations, the file argument is an empty object {} because no specific file is being accessed. Signed download URL generation evaluates read against each stored object's real metadata, including uploadedBy, just like a direct download. Signed upload creation and multipart continuation can still have an empty resource before final file metadata exists.

For the write rule, the file argument type depends on context: during an upload, it is a WriteFileMeta (containing the incoming file's metadata); during a metadata update, it is an R2FileMeta (containing the existing file's stored metadata).

Function Arguments​

ArgumentTypeDescriptionAvailable in
authAuthContext | nullCurrent user (null if unauthenticated). Properties: id, email, role, isAnonymous, custom, metaAll operations
fileR2FileMeta / WriteFileMetaFile metadata (e.g., file.uploadedBy, file.size)All operations

Null Safety​

Since auth can be null (unauthenticated request), always check before accessing properties:

// Good: null check before property access
read(auth, file) {
return auth !== null && auth.id === file.uploadedBy
},

// Bad: will throw if auth is null
read(auth, file) {
return auth.id === file.uploadedBy
},

Multipart Upload Security​

For multipart uploads, the write rule is re-evaluated on every request — create, upload-part, complete, and abort. The uploadId is not treated as a session token. This ensures that a revoked user cannot complete an in-progress upload.

Service Key Bypass​

Requests authenticated with a Service Key bypass all storage access rules:

import { createAdminClient } from '@edge-base/admin';

const admin = createAdminClient('https://api.example.com', {
serviceKey: process.env.EDGEBASE_SERVICE_KEY,
});
// All storage operations bypass rules

See Service Keys for configuration and scoped keys (storage:bucket:photos:read, storage:bucket:*:write, etc.).


See Also