Bucket Policies
Access rules for Abrova Storage buckets. Define read/write/delete/list rules with path patterns, a verified user from the Abrova user token, MIME types, max size, time-based access, and exact IP addresses.
Define access rules for your buckets, similar to Firebase Storage Rules. Control who can read, write, delete and list files based on the signed-in user, paths, and file properties.
A bucket with no rules lets any signed-in user of your app read, upload, delete and list every file in it. Rules apply as soon as a bucket has any — there is no separate switch to turn them on. Requests carrying your server secret skip rules.
Policy Rule Structure#
{
"name": "Rule name (optional)",
"action": "read" | "write" | "delete" | "list" | "*",
"condition": {
"authenticated": true, // A verified user is acting
"pathPattern": "users/{userId}/**", // Path matching
"matchUserId": true, // {userId} must equal the acting user's id
"maxSize": 5242880, // Max file size in bytes
"allowedMimeTypes": ["image/*"], // Allowed MIME types
"validAfter": "2024-01-01", // Time-based access
"validBefore": "2024-12-31",
"allowedIPs": ["203.0.113.7"] // Exact addresses only (no CIDR ranges)
},
"effect": "allow" | "deny",
"priority": 10 // Higher = evaluated first
}How rules are evaluated:
- Rules from all of a bucket's policies are merged and sorted by
priority(higher first; at the same priority,denycomes beforeallow). - The first rule whose action and conditions all match decides:
allowpermits,denyblocks. - If the bucket has rules and none match, the request is denied.
allowedIPsmatches exact addresses only; don't use it to identify end-user devices.
Who the user is#
authenticated and {userId} with matchUserId look at the acting user:
| Request | Acting user |
|---|---|
| App request with a valid Abrova user token (x-user-token) | The token's user, verified by Abrova. |
| App request with a bad or expired token | None: refused with 401 token_invalid / token_expired. |
| App request without a token | None: refused with 401 token_required. The SDKs wait for a token instead of sending it. |
| Server secret | Rules are skipped. |
File requests from apps always need a signed user token (Storage SDK 0.2.1 or newer), so users/{userId}/** always means the verified user. See Overview for how to sign users in, and Security.
A request the rules refuse answers 403 with code access_denied.
Path Patterns#
Path patterns support wildcards similar to Firebase:
{userId}— Captures a single segment; withmatchUserId: trueit must equal the acting user's id.*— Matches a single path segment.**— Matches multiple path segments.
// Examples
"users/{userId}/**" // Matches: users/123/photos/vacation/beach.jpg
"public/*" // Matches: public/logo.png (not subdirectories)
"documents/**/*.pdf" // Not supported - use allowedMimeTypes insteadPre-built Templates#
Use these templates for common access patterns:
publicRead— Any signed-in user can read and list; only authenticated users can write and delete.private— Only authenticated users can access (read/write/delete/list).userFolders— Authenticated users can read and list; they can only write and delete in their own folder (users/{userId}/**).imagesOnly— Authenticated users can upload JPEG, PNG, GIF or WebP up to 5 MB; read and list are open.closed— Server only: an explicit deny for every action from apps. Your server (server secret) still works.
// Apply a template using Node.js SDK
await storageServer.applyPolicyTemplate('my-bucket', 'userFolders');
// Or via API
curl -X POST "https://storage.abrova.ir/api/v1/buckets/bucket_xxx/policies/templates/apply" \
-H "x-api-key: ab_live_xxx" \
-H "x-server-secret: ab_srv_xxx" \
-H "Content-Type: application/json" \
-d '{"template": "userFolders", "name": "User folders policy"}'Creating, changing and deleting rules and applying templates always need the server secret; with the API key alone the API answers 403 server_secret_required. A wrong rule is refused with 400 invalid_rules (the message names the first problem).
Custom Policy Example#
// Create a custom policy for a social media app
await storageServer.createPolicy('user-uploads', [
// Allow users to read their own files
{
name: 'Users can read own files',
action: 'read',
condition: {
authenticated: true,
pathPattern: 'users/{userId}/**',
matchUserId: true,
},
effect: 'allow',
priority: 20,
},
// Allow users to upload images to their folder (max 5MB)
{
name: 'Users can upload images',
action: 'write',
condition: {
authenticated: true,
pathPattern: 'users/{userId}/**',
matchUserId: true,
allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
maxSize: 5 * 1024 * 1024,
},
effect: 'allow',
priority: 20,
},
// Allow users to delete their own files
{
name: 'Users can delete own files',
action: 'delete',
condition: {
authenticated: true,
pathPattern: 'users/{userId}/**',
matchUserId: true,
},
effect: 'allow',
priority: 20,
},
// Public folder is readable by everyone
{
name: 'Public folder is public',
action: 'read',
condition: {
pathPattern: 'public/**',
},
effect: 'allow',
priority: 10,
},
// Everything else is denied (the bucket has rules and none match)
]);