Savvi Studio

Authorization System

This document is the canonical reference for procedure authorization in Studio.

Scope

This system governs authorization for API procedures through procedure metadata and middleware evaluation.

Core implementation points:

  • packages/api-procedure-core/metadata.ts
  • packages/api-procedure-core/middleware.ts
  • packages/api-trpc-context/context.ts
  • packages/api-trpc-context/policy-registry.ts
  • packages/providers-common/graph/modules.ts
  • packages/auth-model/policy-expression.ts

Metadata Model

Procedure metadata uses two top-level sections:

  • execution: runtime hints (for example, requiresTransaction)
  • authorization: access-control contract

Authorization fields:

  • requiresAuth?: boolean
  • requiresAdmin?: boolean
  • requiresRoles?: string[]
  • requiresPermissions?: string[]
  • requireAllRoles?: boolean
  • requireAllPermissions?: boolean
  • expression?: PolicyExpression
  • policyRef?: string
  • policyPreset?: string
  • resolverInput?: Record<string, unknown>
  • policyOverride?: PolicyExpression
  • strict?: boolean
  • allowSystemBypass?: boolean
  • route?: { targetPreset: string }

Policy expression syntax is shared from auth-model and supports:

  • all
  • any
  • not
  • hasRole
  • hasPermission
  • principalType
  • claimEquals
  • claimIn

Resolution Order

When authorization metadata is present, middleware applies this sequence:

  1. Require authentication if any authorization requirement is present.
  2. Apply system bypass only when allowSystemBypass is true and principal type is system.
  3. Evaluate explicit admin/role/permission gates.
  4. Resolve policy expression from metadata resolver:
  • policyRef map
  • policyPreset map
  • resolvePolicyExpression callback
  1. Apply policyOverride if provided (override takes precedence over resolved expression).
  2. Evaluate resulting expression and deny on false.
  3. If strict is true and no policy expression resolved, deny deterministically.
  4. Apply route targetPreset into request metadata.
  5. For admin target presets, elevate require and graph resolution through admin container when available.

Strict Error Contract

For unresolved strict policy metadata, middleware denies with deterministic FORBIDDEN errors:

  • policyRef unresolved: Unresolved policy reference: {policyRef}
  • policyPreset unresolved: Unresolved preset handle: {policyPreset}

For expression denials:

  • policy expression false: Authorization policy denied access
  • direct expression false: Authorization expression denied access

Authentication failure:

  • Authentication required

Policy Handles and Presets

Policy references and presets are resolved from request metadata, assembled from:

  • bootstrap policy registry from installed graph modules
  • per-request resolver maps
  • optional resolvePolicyExpression callback

Graph module codegen can emit policy handle constants. Predicate policy objects can also declare preset values used by resolver metadata.

Route Presets and Elevation

When authorization.route.targetPreset is set:

  • targetPreset is propagated to requestMetadata.routing.targetPreset
  • admin-like targets trigger best-effort elevation via admin container
  • if elevation is unavailable, middleware falls back to existing context services

Current admin target detection:

  • admin
  • app.admin
  • any target ending with .admin

Migration Guide

Legacy capability-style metadata is replaced by authorization and execution blocks.

Before:

  • metadata.capabilities.requiresAdmin
  • metadata.requiresTransaction mixed with auth semantics

After:

  • metadata.authorization.requiresAdmin
  • metadata.execution.requiresTransaction

Recommended migration order:

  1. Move transaction/runtime flags into execution.
  2. Move auth flags into authorization.
  3. Replace direct role/permission gates with policyRef or policyPreset where possible.
  4. Enable strict mode for procedures that require deterministic policy handle resolution.

Validation and Tests

Primary tests for authorization system behavior:

  • integration-tests/api-procedure-core-authorization.workflow.test.ts
  • packages/api-procedure-core/metadata.test.ts
  • packages/api-trpc-context/policy-registry.test.ts
  • packages/graph-module-compile/tests/policy-handles.test.ts
  • packages/graph-module-model/tests/predicate-policy.test.ts

Integration suite command:

  • pnpm test:integration:node

Notes

  • This document describes current runtime behavior.
  • Additional diagnostic event schemas can be layered without changing procedure metadata shape.