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:
projectIdmust be resolved and verified first (seetenancy-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:
- validate input
- resolve
RequestContext(userId,projectId) - evaluate authorization for the operation
- 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-storefor 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
projectIdresolved 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)?