Authorization becomes difficult when an application's rules stop fitting a simple role check. Someone may own a resource, belong to its organization, or inherit access through another resource. Those rules still need to agree wherever the application checks them.
I built author.js to keep that logic in named TypeScript policies that can be shared across the application. Roles, attributes, and relationships can contribute to a decision without each framework integration inventing its own rules.
Making a denied request explainable#
A yes-or-no answer is enough to enforce a permission. It is much less useful when someone needs to understand why access failed.
I separated normal permission checks from full explanations. Normal checks stop once the outcome is known. An explanation evaluates the relevant rules and returns their names and reasons. Deny rules take precedence in both cases, so asking for more detail does not change the answer.
That choice keeps diagnostic work available without making every request pay for a full trace.
Keeping policy growth manageable#
As the number of policies grows, evaluating all of them becomes unnecessary work. I gave policies an explicit scope so a document update can skip rules for unrelated resources or actions before running their checks.
The same policy model supports backend enforcement and permission-aware UI. Storage and framework integrations stay separate from the decision engine, making the rules reusable outside route handlers too.
The part I care most about is being able to trace a decision back to the policy that caused it. Access rules are easier to maintain when their behavior is visible. The policy guide (opens in a new tab) describes how those decisions work.