ctx.db. Protection is
declared once, on the table, and Bijection enforces it on every read and write,
from any function.
Choose a starter
bijection access init writes a starter policy into a project that has no
schema yet. Preview it first; the preview signs in to nothing and writes nothing:
The
team starter declares each team as a tenant boundary and binds every
document to its team through a parent field and index. Membership is an
explicit grant on one team; signing in grants none.
Without --dry-run, setup reports each step separately:
- Source declarations written:
access.ts,schema.tsandaccessApi.ts. - Application deployed: the deployment activated the authorization program.
- Application identity verified: the deployment verified your application sign-in. A management login is never used as an application identity.
- Initial authority established: the verified identity holds
root:owner, the declared recovery role. SetBIJECTION_INITIAL_OWNER, or pass--initial-owner, to require a specific identity. The first caller never becomes an owner implicitly. - Example check: whether that owner may create a document on the root, decided by the installed policy. The check writes nothing; a refusal is reported rather than hidden.
The access model
Thepersonal starter writes this model:
bijection/access.ts
- A permission names one operation on a resource type, such as
document:edit. - A role groups permissions. An assignment gives a holder a role on one resource.
audience: { create: "public" }declares that every caller holdsdocument:create. Creating a document also assignsdocument:ownerto its creator, so a caller without an application identity cannot create one.
The schema
The schema binds thedocument resource to a table. Every field names its
policy, through small constants you reuse:
bijection/schema.ts
defineSchema, defineTable, v and the
access model. assignments stores the application’s role assignments.
Queries and mutations
bijection/documents.ts
createneedsdocument:create, which the model makes public. The server setscreatedBy; a caller cannot choose it.mineis an ordinary query and returns the complete requested range: if any document in it is not readable, for example after its ownership was revoked, the query fails rather than returning a shorter page.mineVisibleadds.visible()and returns only the documents the caller can read, chosen before pagination. Use it when the feature is to discover readable documents.renamecallsrenameDocument, a plain TypeScript helper. It needs no registration, runs in the same transaction, and itsctx.db.patchis checked againstdocument:editat commit, as it would be from any public or internal mutation.removerevokes the document’s assignments, then deletes it withdocument:delete.
select(["_id", "title"]) returns only those fields, and the result type says
so.
Call it from React
Generated references keep argument and result types:results[0]?.title is a string; results[0]?.body is a type error because
the query does not select it.
Share a document
The owner shares a document by granting a role on it. From the command line, signed in as the owner:get the document; rename stays refused. It does not
appear in the viewer’s mine lists, which select by creator. Listing documents
shared with you uses a declared access path; see
read rules. The generated accessApi.grant and
accessApi.revoke functions offer the same operations to the application.
Revoking the assignment affects the viewer’s next reads and live subscriptions.
Add a sensitive field
Adding a field is a classification decision. Suppose owners keep private notes that shared viewers must not read. Declare a permission for them in the model:bijection/access.ts
bijection/schema.ts
privateNotes entry, the table fails type checking and activation
refuses it. document:owner holds document:*, so owners read the notes;
document:viewer and document:editor do not. Reads that viewers make should
select the fields they may read, as mine does.
Who can do what
The initial owner holds
root:owner, which covers every document. Grant it
only to the application’s administrators.
Next steps
- Authorization overview explains the model.
- Read rules covers complete and visible reads, exact selections and indexes.
- Write rules covers creation, field updates and internal mutations.
- Access model covers tenant
boundaries, which the
teamstarter uses.