Architecture Decision Record

0006. Authorization engine and the Authorizer seam

Date: design phase Status: Accepted

Context

The founding ADR left open whether authorization is a Wyrd trait or lives wholly in Vord (ADR-0001 open items; deferred in Wyrd ADR-0018). It is settled here.

The relationship-authorization model — "may principal P do action A on resource R", evaluated over a graph of relations (groups, ownership, sharing, org hierarchy) — is a hard, well-solved distributed-systems primitive. Google's Zanzibar is the reference, and there are mature open implementations of it. Wyrd's own doctrine applies directly: the novelty budget is spent on the differentiator, and the genuinely hard, well-understood primitives are consumed, not reinvented (the reasoning behind Wyrd adopting etcd, Wyrd ADR-0006). Vord's differentiator is the edge-verification composition, not a new authorization engine.

A single-binary / dev profile must also exist with no external dependency, the same constraint that gave Wyrd its embedded-backend pattern.

Decision

  1. Define an Authorizer trait — the policy-decision seam. It evaluates an authorization query and returns a decision, optionally fenced by a consistency token (ADR-0004) when the decision needs read-your-writes (e.g. a just-granted permission).

  2. Pluggable backends, mirroring Wyrd's redb / TiKV split.

    • Production: a Zanzibar-style relationship engine — SpiceDB or OpenFGA — run as a service behind the trait. These provide relation tuples and native consistency tokens ("zookies") that map directly onto the ADR-0004 contract.
    • Dev / single binary: an embedded engine — Cedar (Rust, embeddable) or a minimal built-in relationship evaluator — so the dev profile carries no external dependency, exactly as redb and in-memory coordination do for Wyrd.
  3. The production engine pick (SpiceDB vs OpenFGA) is deferred behind the trait. Both satisfy the contract; the choice is an operational detail and a composition change, not a refactor, so it is safe to defer.

  4. Authorization lives entirely in Vord, not Wyrd. This resolves the Wyrd ADR-0018 deferred question: Wyrd is not in the authorization path. Vord consumes Wyrd's consistency token (ADR-0004), but the relationship store and policy engine are Vord's own.

  5. Relationship-based (ReBAC / Zanzibar) is the primary model, with attribute/role policy (Cedar-style ABAC / RBAC) available for the embedded engine and for policy that does not fit relations. The two coexist behind the trait.

Consequences

  • The hardest correctness-and-scale primitive is adopted, not reinvented — the novelty budget is preserved for Vord's actual differentiator, exactly Wyrd's reasoning for etcd.
  • The dual backend keeps the single-binary dev profile dependency-free while production gets a hardened distributed engine — the same pluggability that lets Wyrd run redb or TiKV behind one trait.
  • The engine's native zookie aligns with the ADR-0004 consistency token, so authz decisions get read-your-writes where needed with no bespoke mechanism.
  • Running a Go service (SpiceDB / OpenFGA) behind the trait is consistent with ADR-0002: Vord-authored code is Rust; adopted engines are any language behind a seam.
  • The deferred production-engine choice is bounded and cheap to make later, because the trait makes it a composition change.