Delegated End-User Isolation
The problem it solves
A Ragty tenant is normally an organization whose own staff search their shared knowledge. But some tenants need to store and serve documents that belong to their external end users — for example a bank that ingests each customer's statements and contracts, or an insurer that holds each policyholder's files.
Without a dedicated mechanism this is unsafe or impractical:
Cross-customer leakage. If customer documents live in ordinary datasets, a retrieval request could surface one customer's documents to another. Ordinary tenant/workspace permissions were designed for staff, not for isolating millions of external end users from each other.
No external identity. End users are not Ragty accounts. There is no Ragty login to attach documents to, and the tenant's own customer identifiers must not be scattered across a second system as plaintext.
Gateway trust. A customer-facing application (a "gateway") searches on behalf of one signed-in customer. A leaked gateway credential must not be able to read every customer's documents.
Delegated end-user isolation solves this by letting a tenant ingest documents owned by external end users and guaranteeing that, through the customer-facing gateway, each end user retrieves only their own documents — never another end user's. Tenant staff (operators) remain fully trusted and can see and maintain all of their tenant's documents; the isolation boundary is strictly end-user vs. end-user, in addition to the usual tenant-vs-tenant boundary.
Core concepts
Concept | Meaning |
|---|---|
Tenant | The organization (e.g. the bank) — the primary storage and authorization boundary |
Operator | Tenant staff who upload and maintain documents and handle support — trusted with all tenant documents |
Delegated subject | An external end user (e.g. a bank customer) — the retrieval-isolation owner |
Trusted issuer | The external identity provider that authenticates end users (not Ragty) |
Identity: issuer + derived subject key
An end user's identifier is issued by an external system, so it is only unique within that issuer. Ragty therefore combines two values:
issuer_id— a stable, server-owned label for one trusted external issuer (for examplebank-customers), defined only in the trusted-issuer registry.external_subject_key— a non-reversible SHA-256 digest derived on the server from the issuer-qualified subject:sha256(issuer_id + separator + subject).
The raw external subject (the customer's issuer-local identifier) is used only to derive the key and is then discarded. It is never persisted, never logged, and never returned to any client. The 64-character key is the only value used as the retrieval isolation predicate.
Optional display label
Because a hash is not human-readable, each subject key can carry an optional operator-facing label (for example the customer's name). The label:
is one value per
(tenant, external_subject_key)— a rename applies to every document with that key;is shown to operators and is searchable (by name or filename), but is never used as an authorization/retrieval filter;
is never shown to end users and never written to the vector store.
How isolation works
Every delegated retrieval on behalf of a verified end user returns only chunks that satisfy:
The "" branch lets an end user also see shared documents that have no delegated owner; another end user's key can never match. This predicate is enforced at a single vector-authorization chokepoint, so it cannot be dropped or weakened by a caller, and applies identically across dense, sparse, and hybrid search on both vector backends.
Operators are not subject to this predicate: a staff search returns the tenant's documents (delegated and non-delegated) under the ordinary tenant and workspace rules.
Where end-user identity enters
There are exactly two boundaries where a raw external subject is accepted, and both immediately derive the key and discard the raw value:
Ingestion. A manifest-driven object-storage datasource lists one record per document with its
issuer_idandsubject. Records with an unknown issuer, a file outside the configured bucket/prefix, or a missing subject are rejected. Operators can also assign an owner (and label) when manually uploading a single document.Retrieval. The customer-facing gateway calls the MCP server with a gateway credential and a verified end-user assertion (a JWT). Ragty verifies the assertion against the issuer's published keys (fail-closed) and derives the same subject key. The assertion is never accepted from a tool argument or request body.
A gateway request without a valid end-user assertion is rejected; it never falls back to a broad, all-customers scope.
Dataset-level ownership
An operator can make a dataset authoritative for a single delegated owner. When a dataset carries an owner:
Every document in the dataset is shown with that owner; it cannot be overridden per document.
Uploading a document to the dataset must resolve to the same owner, or be omitted (and inherit it); a mismatched owner is rejected.
Changing the dataset owner re-assigns the documents that are currently unowned or already carry the previous owner. If any document has a different owner, the change is rejected and the conflicting documents are listed, so nothing is silently overwritten. A preview shows how many documents would change before the operator confirms.
This is managed from the dataset's Delegation tab in the UI.
Security guarantees
One end user can never retrieve another end user's documents through the gateway.
Compromise of a gateway credential alone cannot expose customer documents — a valid, verified end-user assertion is always required.
The raw external subject is never stored, logged, or returned; only the derived key (internal) and an optional operator label (display) exist.
The capability is off by default and enabled by a single configuration gate only after the ownership storage has been prepared and verified; otherwise the server fails closed at startup.