Skip to content
API Now! is currently in closed beta. We are constantly updating these guides as we release updates!

Getting Started with Authorization

Authorization in API Now! defines who can call your endpoints and what data they are permitted to view or modify.

Instead of writing custom authorization code, middleware, or manual SQL filters, you configure declarative Access Scenarios directly in the API Modeler. The platform’s multi-phase authorization engine automatically enforces identity checks, injects row-level SQL filters, and verifies record attributes.


1. The Core Mental Model: Access Scenarios

Section titled “1. The Core Mental Model: Access Scenarios”

An Access Scenario represents a concrete persona or business permission path. Think of an Access Scenario as answering:

“Under what specific conditions should this request succeed, and what data should be returned?”

graph TD
    subgraph "Access Scenarios (Evaluated in Priority Order)"
        S1["Scenario 1: Administrator<br/>(Match User Role: admin)"]
        S2["Scenario 2: Article Author<br/>(Allow Authenticated + Match Resource Owner)"]
        S3["Scenario 3: Public Reader<br/>(Allow Public + Lifecycle Status: Published)"]
    end

Every Access Scenario consists of two types of rules:

  1. Identity-Constraining Rules (WHO): Identifies who the caller is before touching any data. Examples include Allow Public, Allow Authenticated, Match User Role, or Match Organization Role.

  2. Data-Scoping Rules (WHAT): Determines what records the caller can see or interact with. Examples include Match Resource Owner, Match Project Stakeholder, Lifecycle Status, or Match Resource Attribute.


The authorization engine evaluates permissions at two distinct structural levels:

Evaluation LevelStructureLogic & Description
Between Multiple ScenariosPriority List (Top-to-Bottom)“OR ELSE” (Sequential Short-Circuit): Scenarios are evaluated in priority order. The first scenario whose conditions pass grants access. If it fails, evaluation falls through to the next scenario.
Inside a Single ScenarioRecursive Predicate Tree (PredicateGroup)Nested AND / OR Tree: Rules within a scenario are structured as a boolean tree of groups and leaf rules. Groups can be conjoined (AND) or disjoined (OR) and nested to arbitrary depth.

In the API Modeler UI, Access Scenarios are displayed as stacked cards connected by OR ELSE connectors. Inside each scenario card, you construct the authorization logic using a visual predicate tree:

Within each scenario’s predicate tree:

  • AND Groups (style: 'and'): Every child rule or sub-group in the container must evaluate to true. Used to combine prerequisites (e.g., caller must be logged in AND have the editor role).
  • OR Groups (style: 'or'): Access is granted if at least one child branch evaluates to true. Used for alternative access pathways within the same persona (e.g., user is an active organization member viewing shared data OR is a project stakeholder).

Pruning & Unrestricted Access in OR Branches

Section titled “Pruning & Unrestricted Access in OR Branches”

When evaluating an OR group:

  1. Dead Branch Pruning: Branches that fail identity checks during preliminary evaluation are pruned from the active tree. Only surviving branches proceed to generate database queries or verify record attributes.
  2. Unrestricted Access: If any surviving branch in an OR group places no row-level query constraints on the data (for example, an administrator role branch), query scoping is lifted entirely, granting full row access.

API Now! executes authorization across three deterministic lifecycle phases: PRE_FETCH, FETCH, and POST_FETCH.

graph LR
    Req[Incoming Request] --> P1["1. PRE_FETCH<br/>(Identity Gates & DB Pre-flights)"]
    P1 -->|Collection Endpoints| P2["2. FETCH<br/>(Synchronous SQL Query Scoping)"]
    P1 -->|Single-Record Endpoints| DB[Load Hydrated Record]
    DB --> P3["3. POST_FETCH<br/>(Record Attribute Verification)"]
    P2 --> Resp[200 OK Response]
    P3 --> Resp

Phase 1: PRE_FETCH (Identity Gating & Async Pre-Flights)

Section titled “Phase 1: PRE_FETCH (Identity Gating & Async Pre-Flights)”
  • What it does: Evaluates preconditions before any data querying or mutations occur.
  • Checks performed:
    • Identity verification: valid login session, user roles, email domains, IP addresses.
    • Route parameter constraints: verifying parent IDs from route parameters.
    • Asynchronous database pre-flight checks: verifying parent entity ownership or membership pivot records.
    • Pruning: eliminates dead branches from OR groups in the scenario tree.
  • Transparent rules: Data-scoping rules (such as Match Resource Attribute or Lifecycle Status) do not participate in PRE_FETCH and are treated as transparent (true).

Phase 2: FETCH (Synchronous SQL Query Scoping)

Section titled “Phase 2: FETCH (Synchronous SQL Query Scoping)”
  • What it does: Exclusively scopes database query builders for collection endpoints (list, search, restore).
  • Translating AND / OR Trees to SQL: The engine translates the surviving boolean predicate tree directly into an SQL WHERE clause:
    • AND groups translate into query.where(...) subquery wrappers.
    • OR groups translate into query.orWhere(...) subquery wrappers.
  • Strictly Synchronous: To prevent asynchronous query mutation race conditions, the query builder is scoped synchronously without async database lookups.
  • Exact Pagination Guarantee: Because row-level filtering happens entirely in SQL via WHERE, WHERE IN, and correlated WHERE EXISTS clauses, SQL pagination totals (meta.total, page, per_page) remain 100% exact without in-memory hole punching.

Phase 3: POST_FETCH (Record Attribute Verification)

Section titled “Phase 3: POST_FETCH (Record Attribute Verification)”
  • What it does: Evaluates post-conditions on hydrated resource models for single-record actions (read, create, update, delete, link, unlink).
  • Checks performed: Verifies attributes on the loaded record (e.g. matchResourceAttribute or lifecycleStatus) against the winning scenario.

4. The Scenario Hierarchy (API, Entity, and Action Levels)

Section titled “4. The Scenario Hierarchy (API, Entity, and Action Levels)”

To prevent repetitive configuration, you can attach Access Scenarios at three different levels of your API Model:

graph TD
    API["1. API Model Level<br/>(Global baseline defaults)"] -->|Inherited by| Entity["2. Exposed Entity Level<br/>(Applies across all actions of an entity)"]
    Entity -->|Inherited by| Action["3. Action Level<br/>(Highest priority: specific endpoint rules)"]

When an action executes, the authorization engine merges scenarios from all three levels in order of specificity:

Effective Scenarios=Action Scenarios⟶Entity Scenarios⟶API Model Scenarios\text{Effective Scenarios} = \text{Action Scenarios} \longrightarrow \text{Entity Scenarios} \longrightarrow \text{API Model Scenarios}

  1. Action Level (Evaluated first / Highest priority): Endpoint-specific scenarios (e.g., custom rules for DELETE /articles/:id).
  2. Exposed Entity Level (Evaluated second / Medium priority): Common scenarios shared across all operations on that entity (e.g., default access for /articles).
  3. API Model Level (Evaluated last / Lowest priority): Global baseline scenarios that apply across your entire API unless handled earlier.

Isolating Sensitive Endpoints (“Override Parent Scenarios”)

Section titled “Isolating Sensitive Endpoints (“Override Parent Scenarios”)”

Sometimes an individual action needs strict security that should not inherit broader parent policies. For example, you might allow general users to read articles at the entity level, but you want the DELETE action to strictly require an Administrator role.

In the action settings, you can check “Override parent scenarios”:

  • When disabled (default): The action evaluates its own scenarios first, then falls back to entity-level and API-level scenarios.
  • When enabled: The action ignores all entity and API-level scenarios. Only the scenarios explicitly defined on this action are evaluated.

5. Ordering Your Scenarios: Specific First, Broad Last

Section titled “5. Ordering Your Scenarios: Specific First, Broad Last”

Because scenarios are evaluated in top-to-bottom priority order (“OR ELSE”), the order of your scenarios matters.

Always order your scenarios from most specific (narrow persona) to most general (broad persona):

✅ Correct Order:
1. Scenario A: Administrator (Match User Role: admin) <- Specific / Privileged
2. Scenario B: Team Member (Match Org Role + Stakeholder) <- Specific / Scoped
3. Scenario C: Public Catalog (Allow Public + Published) <- Broad / Catch-all

Example 1: Multi-Persona Project Directory (GET /orgs/:oid/projects)

Section titled “Example 1: Multi-Persona Project Directory (GET /orgs/:oid/projects)”
  • Goal: Expose a single endpoint where:
    • Administrators have unrestricted access to all projects.
    • Organization members see public and org-shared projects, OR any private project where they are a stakeholder (owner or member).
    • External visitors or non-org users see only public projects.
# GET /orgs/{oid}/projects
scenarios:
# Scenario 1: Admin
- label: 'Administrator'
predicate:
style: and
children:
- Allow Authenticated
- Match User Role: ['admin']
# Scenario 2: Org & Project Members
- label: 'Org and Project Members'
predicate:
style: or
children:
# Branch B: Org member viewing shared projects
- style: and
children:
- Match Organization Role: any
- Match Resource Attribute: status in ['org', 'public']
# Branch C: Stakeholder projects (owner or member)
- style: and
children:
- Allow Authenticated
- Match Project Stakeholder
# Scenario 3: Public Catalog (Evaluated OR ELSE)
- label: 'Public Catalog'
predicate:
style: and
children:
- Allow Public
- Match Resource Attribute: status in ['public']

For an organization member who is also a project stakeholder, Scenario 2 matches, and the FETCH phase translates the OR group directly into SQL:

SELECT projects.*
FROM projects
WHERE projects.organization_id = :oid
AND (
-- Branch B: Shared org projects
projects.status IN ('org', 'public')
-- Branch C: Projects where caller is a stakeholder
OR (
projects.owner_id = :currentUserId
OR EXISTS (
SELECT 1 FROM project_members
WHERE project_members.project_id = projects.id
AND project_members.user_id = :currentUserId
)
)
)
PersonaScenario 1 (Admin)Scenario 2 (Org & Stakeholder)Scenario 3 (Public)Results Returned
AdminPASS (Wins)Not evaluatedNot evaluatedAll projects in the organization (unfiltered).
Org MemberFails (not admin)PASS: Branches B & C surviveNot evaluatedOrg-shared projects + projects where user is owner/member.
Non-Org UserFailsFails (not in org, no projects)PASSOnly projects marked public.
AnonymousFailsFails (not authenticated)PASSOnly projects marked public.

  • Goal: Admins manage everything, authors manage their own articles, and public visitors read published posts.
  • Scenarios on Article:
    • Scenario 1 (Admin): Allow Authenticated + Match User Role: ['admin', 'editor'] (Unfiltered access).
    • Scenario 2 (Author Workspace): Allow Authenticated + Match Resource Owner (Own articles).
    • Scenario 3 (Public Readers): Allow Public + Lifecycle Status: ['published'] (Published articles only).

  • Goal: Users can update their own account details, but cannot edit other users’ profiles.
  • Scenarios on User Update action:
    • Scenario 1 (Admin Override): Match User Role: ['admin'].
    • Scenario 2 (Self Update): Allow Authenticated + Match Resource Owner.
    • Action Setting: Enable “Override parent scenarios” so general read rules don’t permit unauthorized profile updates.

Explore the complete reference for authorization strategies and individual access rules: