
# Bucket Permissions

A bucket's `permissions` block answers one question per operation: who may do this? It uses the same three-shape `PermissionValue` format as [table permissions](/en/docs/table-permissions), so nothing new has to be learned to read it.

| Value             | Means                                         |
| ----------------- | --------------------------------------------- |
| `all`             | Everyone, including unauthenticated requests. |
| `authenticated`   | Any user with a session, whatever their role. |
| `[admin, editor]` | Only the listed roles.                        |

```yaml
buckets:
  - name: documents
    maxFileSize: 52428800
    allowedMimeTypes: [application/pdf, text/csv]
    permissions:
      upload: [admin, editor]
      download: authenticated
      sign: authenticated
      signUpload: [admin, editor]
      delete: [admin]
```

## The Five Operations

| Operation    | Governs                             | Default when omitted                                |
| ------------ | ----------------------------------- | --------------------------------------------------- |
| `upload`     | Writing a new file into the bucket. | `authenticated`                                     |
| `download`   | Reading a file back out.            | `all` on a public bucket, `authenticated` otherwise |
| `sign`       | Minting a signed **download** URL.  | `[admin]`                                           |
| `signUpload` | Minting a signed **upload** URL.    | `[admin]`                                           |
| `delete`     | Removing a file from storage.       | `[admin]`                                           |

Omitting `permissions` entirely applies every default above. The consequence worth internalising: **signing is admin-only until you say otherwise**. A bucket that a `member` should be able to hand out download links for needs `sign: authenticated` written down; silence means no.

## What Is Enforced Today

`sign` and `signUpload` are enforced by the signing endpoints, with role resolution and an admin override. The other three are declared in the schema but not yet consulted by the bucket file routes, which gate on the bucket's `public` flag and the presence of a session instead:

| Request                                        | Answer                                             |
| ---------------------------------------------- | -------------------------------------------------- |
| Upload or delete on a **public** bucket        | Allowed, session or not.                           |
| Upload or delete on a **private** bucket       | `401` without a session; allowed with one.         |
| Download on a private bucket, no session       | `404` (anti-enumeration — never `403`).            |
| Sign without a session                         | `401`.                                             |
| Sign with a session but no matching permission | `404`, so the permission boundary stays invisible. |

:::callout
**Treat `upload` / `download` / `delete` as intent, not as a fence — for now.** Write them down: they are the schema's record of what you meant, they survive into `sovrium validate`, and they are what the enforcement path will read. But do not put a private bucket behind a role list and assume a `member` is excluded from uploading today. If a boundary has to hold right now, express it with `public: false` plus the [signed-URL flow](/en/docs/signed-urls), whose permissions _are_ checked.
:::

## Admin Override and Anonymous Callers

Two rules cut across every signing check:

- **`admin` always passes.** A role named `admin` can sign on any bucket regardless of what the permission lists.
- **`all` still needs a session on the signing endpoints.** The signing routes reject anonymous callers with `401` before any permission is evaluated, so `sign: all` widens access to _every logged-in user_, not to the public. To serve files without a session, make the bucket `public: true` — that is the switch for anonymous reads.

## Related Pages

- [Buckets Overview](/en/docs/buckets-overview) — the bucket a permission block belongs to.
- [Storage Backends](/en/docs/buckets-backends) — where permitted bytes are written.
- [Signed URLs](/en/docs/signed-urls) — the flow that reads `sign` and `signUpload`.
- [Roles & RBAC](/en/docs/auth-roles-rbac) — where the role names come from.
- [Table Permissions](/en/docs/table-permissions) — the same value format on tables.
