Scopie is a small, explicit, scope-based authorization engine.
It evaluates hierarchical permission patterns against requested actions using a deterministic, spec-defined algorithm. Scopie is designed to be embedded directly into applications and services, without requiring a policy server, DSL, or external data source.
Scopie follows clarity and explicit behavior over flexibility.
Scopie is currently in alpha.
Behavior is versioned and defined by the scenarios.json file.
Implementations are expected to conform exactly to the scenarios for their supported version.
- A deterministic scope evaluator
- Based on hierarchical paths, wildcards, arrays, and variables
- Explicit allow vs deny semantics
- Langauge agnostic via a shared specification
- Easy to reason about and test
- ??? data owned by you
- A policy engine
- A role management system
- An attribute-based authorization framework
- A centralized policy service
If you need expressive policy languages, dynamic external lookups, or centralized policy distribution, Scopie is likely not the right tool.
A permission that would allow or deny access:
allow:blog/read
deny:admin/**
An action is a concrete request being evaluated:
blog/read
Scopie evaluates an action against a set of granted permissions.
Permissions are hierarchical and path-based.
*matches exactly one path segment**matches one or more path segments- Arrays (
|) match one of several values
Examples:
allow:blog/*/read
allow:admin/**
allow:reports/public|private/read
Permissions may include variables that are substituted at evaluation time:
allow:tenant/@tenant_id/**
Variables are simple substitutions, not expressions or conditions.
Scopie's evaluation rules are intentionally simple and explicit.
Given a set of permissions and an action:
- Permissions are evaluated in sequence.
- If a matching deny permission is found, evaluation immediately stops and access is denied.
- If a matching allow permission is found, it is recorded and evaluation continues only for deny permissions.
- If evaluation completes with at least one matching allow and no matching deny, access is allowed.
- If no permissions match, access is denied.
This short-circuit behavior is deterministic and does not affect the final result:
- Deny always overrides allow
- Permission order does not change outcomes
Scopie is spec-first.
The scenarios.json defines the normative behavior of Scopie across:
- Allow and deny precedence
- Wildcard and super-wildcard semantics
- Variable substitution
- Invalid input handling
- Determinism and order invariance
- A cross-language conformance suite
All Scopie implementations must conform to these scenarios. If you want to understand exactly how Scopie behaves, then this is the place to look.
Scopie is implemented across multiple languages, all conforming to the same specification:
A portion of our application is around building, running and responding to financial reports. We run half, quarterly, monthly and weekly reports.
Verbs
- Edit: Modify how the report is built
- Run: Manually run the report
- Read: Read the reports in our tool
- Approve: Sign off on the report, approved reports would then be shared
- Delete: Remove an invalid or broken report
Format
For the above reasons we are going to specify our permissions and actions as:
reports/<duration>/<verb>
We could expand this later to include some sort of organization or business group but for this example, we will keep it simple.
Users
- Maya is allowed to do everything ( the boss )
allow:**
- Adam is allowed to edit and read any report ( makes changes to the queries )
allow:reports/*/edit|read
- Tyler can only read reports ( reviews reports but doesn't need to approve them )
allow:reports/*/read
- Elisa can do everything but delete ( mostly there to approve, but occasionally edits queries )
allow:reports/*/*
deny:reports/*/delete
- Jenna can edit and read but only the weekly reports ( a new hire working up )
allow:reports/weekly/edit|read