Skip to Content
🎉 TestoQA 1.0 is released
Developer GuideArchitectureAuthorization model

Authorization Model

1. Authorization Goals

Authorization in TestoQA must ensure:

  • Users can only access data within projects they belong to
  • Permissions are evaluated per (user, projectId)
  • Checks occur server-side before tenant data is read or mutated
  • The UI may adapt to permissions, but never enforces them

Authorization is implemented using a capability/ability model (CASL), but this document focuses on behavior and enforcement, not library specifics.


2. Role vs Capability Model

TestoQA uses roles to simplify management, but enforcement is based on explicit capabilities (abilities).

  • Role: a named bundle of permissions (e.g., Owner, Admin, Member, Viewer)
  • Ability/Capability: an atomic permission (action + subject + conditions)

The system should be able to answer:

“Within this project, can user X perform action Y on subject Z?”


3. Ability Derivation

Abilities are derived from:

  • authenticated identity (userId)
  • project membership (membership record)
  • role within the project
  • optional conditions (ownership, state, etc.)

Derivation requirements

  • Ability derivation must be deterministic
  • Ability derivation must not depend on client state
  • Ability derivation must be performed server-side

4. Project Membership and Scope

A user may belong to multiple projects.

Authorization scope is always bounded by the resolved tenant context:

  • projectId must be resolved and verified first (see tenancy-model.mdx)
  • membership checks are performed against that projectId
  • authorization decisions are then made within that project scope

Rule: No authorization decision is valid without an explicit projectId.


5. Enforcement Locations

Authorization must be enforced at the system boundary, and optionally reinforced in sensitive services.

Primary enforcement: Boundaries

Server Actions and Route Handlers must:

  1. validate input
  2. resolve RequestContext (userId, projectId)
  3. evaluate authorization for the operation
  4. only then access tenant data via services/repositories

Secondary enforcement: Sensitive services

Services that coordinate multi-step operations or security-sensitive workflows may perform additional checks to protect against accidental bypass.

This is defense-in-depth, not a replacement for boundary enforcement.


6. Authorization Semantics

Authorization decisions typically follow:

  • Action: create | read | update | delete | execute | manage (example set)
  • Subject: domain object type (e.g., TestCase, TestRun, Report, Upload, Project)
  • Conditions: optional constraints (e.g., “only within this project”, “only if owner”)

Tenant constraints are mandatory

For tenant-scoped subjects, the project constraint is implicit and required:

  • No cross-tenant subjects
  • No “global read” of tenant data
  • Any subject lookup must not leak across tenants

7. UI vs Server Responsibility

UI responsibilities

  • Hide or disable actions the user cannot perform
  • Provide affordances that match permissions
  • Handle 403 responses gracefully

Server responsibilities (non-negotiable)

  • Enforce authorization before data access
  • Ensure tenant scoping is applied in all queries
  • Return safe errors without leaking sensitive information

8. Authorization Failure Handling

Authorization failures must be:

  • safe: reveal minimal information
  • consistent: same handling patterns across modules
  • observable: logged/metric’d appropriately without leaking data

Common failure types

  • Unauthenticated (no session): treat as 401/redirect (see auth-flow.mdx)
  • Unauthorized (no permission within project): 403 (or equivalent)
  • Tenant mismatch (resource not in resolved project): treat as unauthorized or not found, depending on endpoint semantics

The system should prefer not to reveal whether a resource exists in another tenant.


9. Caching and Authorization Safety

Authorization-dependent data must not be cached in a way that could leak across users or tenants.

Rules:

  • Prefer no-store for permission-sensitive reads
  • If caching is used, cache keys must include:
    • tenant scope
    • and user scope when permissions vary by user

10. Review Checklist (Authorization)

  • Is projectId resolved and membership verified before authorization?
  • Are checks performed before tenant data access?
  • Do boundaries enforce permissions consistently?
  • Are sensitive services protected with defense-in-depth where appropriate?
  • Are 403/unauthorized responses tenant-safe (no cross-tenant leakage)?
  • Is caching safe for permissioned data (or disabled)?
Last updated on