check(user:visitor, can_view, page:peretyn)allowed
write(page:peretyn#visitor@user:visitor)you arrived, that's a relation
Access is an intersection.
peretyn is a TypeScript-first ReBAC platform, powered by OpenFGA. Model who can do what as relationships, check it in microseconds, ship it like infrastructure. Open source soon.
This page runs on a peretyn model. You start with one relation and earn the rest as you scroll. The tour never blocks anything, and you can skip to the waitlist.
page:peretyn#readergranted as you go
Roles stopped scaling the day you shipped sharing.
Every product grows the same knot. Owners, teams, folders, shared links, an admin who can see everything except payroll. Each rule lands as another if, copied into every service that needs it.
function canEdit(user: User, doc: Doc) {
if (user.role === 'admin') return true;
if (doc.ownerId === user.id) return true;
if (doc.teamId && user.teamIds.includes(doc.teamId) && user.role !== 'guest') return true;
if (doc.sharedWith?.some((s) => s.userId === user.id && s.level !== 'view')) return true;
if (doc.folderId && canEditFolder(user, doc.folderId)) return true; // recursion, hopefully
return false; // TODO: org admins, link sharing, audit log, that one enterprise customer
}Relationship-based access control models it as a graph instead: who relates to what, and how permissions follow those relations. Google built Zanzibar on this idea. OpenFGA made it open. peretyn makes it pleasant.
page:peretyn#editorgranted as you go
Your permission model is TypeScript.
Declare types, relations and permissions with defineSchema. Every type and relation you pass to check is verified when you compile, so a typo is a red squiggle, not an incident. Try a wrong relation name below.
user:visitor can_edit document:launch-plan deniedYou're an editor of launch-plan, but can_edit only counts owners.
page:peretyn#checkergranted as you go
Checks in tens of microseconds.
The runtime is Go on OpenFGA. A check costs it tens of microseconds, so your latency budget goes on the network, not the decision. Batch checks, lookups in both directions and a changelog for sync come with it.
This console runs against the model behind this page. Ask it anything about yourself.
await authz.check({subject: user:visitor,object: page:peretyn,})Runs against the relations you've earned so far.
page:peretyn#deployergranted as you go
Ship permissions like infrastructure.
build compiles your schema to an artifact. plan shows exactly what will change. apply deploys it under a version label. test runs your assertions against a live environment. The same token your SDK uses picks the environment, so there are no ids to copy around.
page:peretyn#operatorgranted as you go
Hosted by us, or run on your own hardware.
Hosted
We run the runtime, control plane and dashboard on app.peretyn.dev. Free during early access.
Self-hosted
Postgres, the Go runtime, the control plane and the dashboard behind Caddy, on one host.
curl -fsSLO "$base/compose.yaml"
curl -fsSLO "$base/Caddyfile"
docker compose up -dThe source opens soon. The license is already MIT, so whatever you build on peretyn stays yours either way.
page:peretyn#provergranted as you go
Here's why you're allowed in.
expand returns the proof behind any decision, so "why can this person see that?" has an answer you can read. Here is yours, for joining the waitlist.
Get early access.
The hosted platform opens to the waitlist first, free while it's in early access. You'll get one email when it's your turn.