Skip to content

Permissions

Control file access with Hasura's permission system

storage permissions access control Hasura authorization roles security

File permissions control who can upload, download, replace, and delete files. They are managed per role in the dashboard.

Permissions follow a Zero Trust model — by default no role has access. Access must be explicitly granted.

Storage supports four permission actions:

  • Upload — who can upload new files
  • Download — who can view and download files
  • Replace — who can overwrite existing files
  • Delete — who can remove files

In the dashboard, navigate to Storage and click Permissions at the bottom of the sidebar to see the permission grid. This grid shows every role and action at a glance — full access, partial access, or no access. Click any cell to configure that role’s permission for that action.

Permission grid

Each action form has the following options:

  • Without any checks — the role can perform the action on all files, no conditions.
  • With custom check — use the rule editor to restrict which files the role can access (e.g. only files in a specific bucket, or only files the user uploaded).
  • Permission presets — pre-built rules for common patterns.

Download permission form

The Upload and Replace forms have an additional toggle:

  • Uploader identity — automatically sets uploaded_by_user_id to X-Hasura-User-Id when files are created or replaced. This ensures every file is tagged with the uploader’s identity without relying on the client to send it.

Upload permission form

Private Files — Users Access Only Their Own Files

Section titled “Private Files — Users Access Only Their Own Files”

The most common pattern. Users can upload, download, and delete only files they own, in a specific bucket.

In the permission grid, click the Upload cell for the user role.

  1. Select With custom check and add a rule: bucket_id equals personal
  2. Under Uploader identity, enable the Prefill uploaded_by_user_id with X-Hasura-User-Id toggle to automatically tag files with the uploader’s identity

Files in a public bucket can be downloaded by anyone (including the public role), but only authenticated users can upload.

Configure the Upload action for the user role:

  1. Select With custom check and add a rule: bucket_id equals public
  2. Under Uploader identity, enable the Prefill uploaded_by_user_id with X-Hasura-User-Id toggle

Multi-Tenant — Organization-Scoped Files

Section titled “Multi-Tenant — Organization-Scoped Files”

For multi-tenant applications where files belong to an organization. This uses a custom claim X-Hasura-Org-Id.

This example assumes you have a relationship from storage.files to your organizations table through a custom org_id column in your file metadata or through a linking table.

A simpler approach uses the file’s custom metadata JSONB column to store the organization ID, and a Hasura computed field or relationship to evaluate it.

Alternatively, you can create a dedicated organization_files table that references storage.files:

CREATE TABLE public.organization_files (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
file_id uuid NOT NULL REFERENCES storage.files(id) ON DELETE CASCADE,
org_id uuid NOT NULL REFERENCES public.organizations(id)
);

Then set permissions on this linking table using X-Hasura-Org-Id, and configure a relationship from storage.files to organization_files. For the storage permissions themselves:

Configure the Upload action for the user role:

  1. Select With custom check and add a rule: bucket_id equals org-files
  2. Under Uploader identity, enable the Prefill uploaded_by_user_id with X-Hasura-User-Id toggle

Different roles get different levels of access. For example, editor can upload and delete, while viewer can only download.

Upload: Select With custom check if you want to restrict to specific buckets, or Without any checks for all buckets. Under Uploader identity, enable the Prefill uploaded_by_user_id with X-Hasura-User-Id toggle.

Download: Select Without any checks — editors can view all files.

Delete: Select With custom check and add a rule: uploaded_by_user_id equals X-Hasura-User-Id. This lets editors delete only their own uploads.

  • Under Uploader identity, enable the Prefill uploaded_by_user_id with X-Hasura-User-Id toggle on Upload and Replace permissions to prevent users from impersonating others.
  • Use custom checks on bucket_id to control which buckets a role can access.
  • Use the public role for files that should be accessible without authentication.
  • Combine bucket restrictions with ownership checks for fine-grained control.
  • Test permissions by signing in as different users and verifying access is correctly scoped.

Storage permissions are built on Hasura’s permission system for the storage.files table. The dashboard configures these automatically, but understanding the underlying mapping can help with debugging or advanced setups.

When a user makes a request to the Storage API:

  1. The Storage service extracts the JWT from the Authorization header
  2. The JWT contains the user’s ID, role, and any custom claims
  3. Storage forwards these as Hasura session variables (X-Hasura-User-Id, X-Hasura-Role, etc.)
  4. Hasura evaluates the permission rules for the storage.files table
  5. If the permission check passes, the operation proceeds

The following session variables are available in custom checks:

  • X-Hasura-User-Id — the authenticated user’s ID
  • X-Hasura-Role — the user’s role
  • Custom claims like X-Hasura-Org-Id

Each dashboard action maps to a Hasura permission on the storage.files table:

ActionHasura PermissionRequired Columns
Uploadinsertid, bucket_id, name, size, mime_type
DownloadselectAll columns must be granted
Replaceupdatebucket_id, etag, is_uploaded, metadata, mime_type, name, size
Deletedelete