Access control is opt-in per request. A query without an
acl field is not filtered. Adding ACLs to your documents changes nothing until your queries start declaring who is asking.1. The two halves
Access control only works when both halves are in place. Either half alone is a no-op.2. Principals
A principal is an identity represented by a string: a user, a group, or everyone in a domain. These are the five supported forms:
Principals are lowercased, trimmed, and deduplicated on the way in.
__public__ overrides everything else in the same list: a document that is public is public. A list containing __private__ alongside real principals keeps the real principals and drops the sentinel; __private__ only means something on its own.
Limits: 1000 principals per document, 256 characters per principal. For larger groups, use a group: or domain: principal.
3. Set an ACL
At ingest, on an app source
Each item inapp_knowledge accepts an acl list:
acl and the document is unrestricted. A malformed principal rejects the whole request with 400 rather than ingesting the document unprotected.
On an existing source, without re-ingesting
PATCH /context/{id}/metadata accepts acl and replaces the stored list:
An
acl-only body is a valid edit; you do not have to send metadata alongside it.
On a connector resource
Every object synced from a resource inherits the resource’s rule. Set it when you configure the connector:["__public__"] to open a resource back up.
4. Let connectors capture permissions for you
For supported providers, HydraDB reads the source app’s own permissions on every sync and applies them as ACLs, so you do not maintain a parallel permission model.
Capture is also built for other providers, including GitLab, Linear, Dropbox, Zendesk and PagerDuty, and is switched on per provider. For any other provider, set a rule per resource with
acl, as described above.
If HydraDB cannot read a resource’s permissions from the provider, a resource with no rule of yours is readable by everyone until the next successful read, while a rule you set still applies. Get Connector Status reports an acl_warning on the resource meanwhile.
Precedence, when both exist:
- A per-document permission from the provider (a Drive file’s own sharing) wins over everything.
- A provider verdict of “this resource is public” will not override a rule you set. Restricting a public channel is a deliberate act, and enabling capture never widens it back.
- Otherwise the provider’s resource-level verdict wins over your rule, because the provider is the fresher source of truth.
Capture can be turned off per provider without a deploy.
5. Query on behalf of someone
Pass the caller’s identity asacl on POST /query (and POST /context/list, which takes the same field with the same meaning):
- its stored ACL is absent (unrestricted),
- it is
__public__, - its ACL contains one of the caller’s principals.
__public__is added for you: You never have to ask for public content.- The domain principal is derived from the email: Querying as
grace@acme.comautomatically matches anything shared withdomain:acme.com.
"acl": ["grace@acme.com", "group:slack:C0123"].
Access control composes with, and is independent of, metadata filters: filters express what you are looking for, ACLs express what you are allowed to find. A caller cannot widen their own visibility with a filter.
6. Revoking access
Deleting a rule does not widen access on its own: visibility only ever widens from a value you positively set. To open a restricted resource back up, set its ACL to
["__public__"] rather than clearing it.
7. Common mistakes
ACLs are set but every query still returns everything
ACLs are set but every query still returns everything
The queries are not declaring an identity.
acl is opt-in per request; without it there is no filtering. Add "acl": ["<caller email>"] to the query.A caller who should see a document sees nothing
A caller who should see a document sees nothing
Check the principal forms on both sides.
group:slack:C0123 on the document only matches a query that declares that same group; unlike domain:, group membership is not derived from the caller’s email. Also confirm the email matches exactly: principals are compared after lowercasing and trimming, but not otherwise fuzzy-matched.Related
- Connectors: syncing app data, and per-resource ACL rules
- App Sources: the ingest shape that carries
acl - Query: the
aclfield alongside every other retrieval parameter - Metadata: filtering by attributes, a different question from permission
- Multi-Tenant Support: databases and collections, the isolation boundary ACLs work inside
- Update Source Metadata (API Reference): the
aclreplacement contract
