# ADR 005: Authorization Model

- HTML version: https://robbiepalmer.me/projects/recipe-site/adrs/005-authorization-model
- Project: Recipe Site (https://robbiepalmer.me/projects/recipe-site.md)
- Status: Accepted
- Date: 2026-05-27
- Initiatives: Digital Twins for Everyday Life (https://robbiepalmer.me/initiatives/digital-twins-for-everyday-life.md)

# Summary

Enforce Recipe Site visibility and mutation rules in the application service
with explicit public, user, and household scopes. Browser visibility is never
an authorization boundary.

[PDR 003](/projects/recipe-site/pdrs/003-private-user-state-and-household-sharing)
owns the product policy for public recipes, private user state, and
household-first sharing. This ADR defines the technical model that enforces it.

# Context

Authentication identifies a user. It does not determine which user or household
owns a record, whether that record is public, or which actions a current
household member may perform.

The backend needs one authorization path for route handlers, background work,
and later delegated agents. Hiding a control in React cannot protect the API,
and treating a Better Auth organization membership as permission to every
household resource would bypass resource audience and custody rules.

# Decision

Represent a protected resource with an explicit scope and custody reference:

* public scope permits anonymous reads and never implies anonymous writes;
* user scope names the user who controls the resource;
* household scope names the household that controls the resource;
* a user-owned resource may separately grant its current household read access
  without changing custody.

Resolve the authenticated actor at the `recipe-api` boundary. Load current
resource scope, custody, audience, and household membership from authoritative
server state. Pass that context to domain authorization functions before a
read or mutation reaches its repository operation.

The initial roles stay small. A resource custodian can read, edit, delete, and
change its audience. A household owner can manage household membership and
household-governed resources. A household member receives only the access that
the resource policy grants. PDR 000 later permits active members to edit a
household-maintained recipe branch while keeping personal shared recipes under
their user's custody.

Membership invitations, removals, custody transfers, publication, and audience
changes require server-side checks inside the same operation that changes the
protected state. A membership change must invalidate or bound cached access,
live subscriptions, and delegated permissions.

Use the same policy functions for HTTP routes, Workflows, administrative tools,
and agent capability handlers. Every path supplies an authenticated or
anonymous actor and the target resource context. No internal caller receives
implicit permission merely because it runs behind the public API.

# Verification

Authorization tests cover each resource and action across anonymous visitors,
the user custodian, household owners, current members, former members, and an
unrelated signed-in user. Tests also cover audience changes, membership removal,
and stale delegated or realtime access.

The application must return the same denial for a hidden resource and an
unknown resource when revealing existence would leak private state. Logs may
record stable internal identifiers and the policy result, but not private
recipe, pantry, or household content.

# Consequences

The database and API have a concrete scope model that implements the product
policy without introducing a general RBAC or ABAC engine. Authorization logic
remains application code, which needs shared functions and exhaustive tests to
avoid route-specific drift.

Future direct friend sharing, new household roles, public API scopes, or
cross-household collaboration require a new product decision before expanding
this model. A later architecture decision can then add the smallest policy
mechanism needed for that accepted behavior.

# Migration note

The original ADR mixed the product visibility and sharing policy with its
enforcement model. PDR 003 now owns the product choice. This structural edit
retains the accepted server-side scope and authorization decision without
changing access behavior.

---

Markdown index of this site: https://robbiepalmer.me/llms.txt
