Authorization & RBAC

Deciding what an authenticated principal may do. BitVault uses a layered RBAC + ABAC + ReBAC model evaluated by a deny-by-default policy engine (Cedar). Implements ADR-0010. Closes OWASP API1 (BOLA), API3 (BOPLA), and API5 (BFLA) — three of the top five API risks.

:::warning Deny-by-default Missing authorization checks default to denial, not permission. Every new endpoint must have an explicit authorization annotation. Absence of a grant is a 403, never a 200. :::


1. Policy Model: PEP → PDP, Deny-by-Default

flowchart LR
    classDef e fill:#fde68a,stroke:#b45309,color:#111827;
    classDef p fill:#bbf7d0,stroke:#15803d,color:#111827;
    classDef d fill:#c7d2fe,stroke:#3730a3,color:#111827;
    req["request"]:::e --> pep["PEP (gateway / service): intercept every access"]:::e
    pep --> pdp["PDP: Cedar evaluate(principal, action, resource, context)"]:::p
    rebac["ReBAC graph (sharing / membership)"]:::d --> pdp
    rbac["RBAC roles"]:::d --> pdp
    abac["ABAC attributes: tags, classification, residency"]:::d --> pdp
    pdp --> dec{"permit / forbid (deny-by-default)"}:::p
    dec -->|permit + obligations| act["allow (+ watermark / log / step-up)"]:::e
    dec -->|forbid| block["403"]:::e

2. RBAC Roles

Scope Roles
Tenant / Organization owner · admin · member · billing · auditor (read-only audit)
Resource (via ReBAC sharing) owner · editor · commenter · viewer
Machine / Service account Service-account roles + API-key scopes (always a strict subset of the principal’s rights)

Each tenant has its own role namespace. A principal’s effective permission is role capabilities ∪ ReBAC grants ∩ API-key scope, evaluated by Cedar. Separation of duties is built in: auditor reads the audit log but cannot mutate data; billing cannot read files.


3. Object-Level Authorization (BOLA Defense)

BOLA (Broken Object Level Authorization) is the #1 API risk precisely because it is easy to check “is the user logged in?” and forget “does this user own this specific object?”.

Every resource access runs a PDP check against the specific object — not just the user’s role. Postgres RLS acts as a backstop: even if an application-layer check is omitted, the database returns no rows for objects belonging to another tenant.


4. Field-Level Authorization (BOPLA Defense)

API responses and incoming request bodies use explicit allow-listed DTOs. Fields are never copied from raw input to domain models; each role sees only the fields it is permitted to read or write. This closes OWASP API3 (Broken Object Property Level Authorization) — both excessive data exposure (reading) and mass assignment (writing).


5. Function-Level Authorization (BFLA Defense)

Every gRPC method has an explicit role check. Admin endpoints require the admin or owner role and are additionally audited. The gateway enforces these checks before routing; services re-check on the verified internal auth context. There is no route that defaults to “allow all authenticated users”.


6. Scopes & Least Privilege for Machines

API keys and service accounts carry OAuth-style scopes (files:read, files:write, shares:create, optionally scoped to resource prefixes). A key’s scope is a strict subset of its principal’s rights — it can never exceed them. Default scope on issuance is minimal; additional scopes must be explicitly requested and granted.


7. Privilege-Escalation Prevention


8. Public Sharing Authorization

A public share token is treated as a capability: the anonymous holder is authorized for exactly the shared node, the granted permission level, and the time window — nothing else. Every presigned-URL issuance for a share re-validates the share record and the principal’s authority to grant access before issuing the URL.


9. Threats Addressed

Threat Control Residual
Cross-object / cross-tenant access (BOLA) PDP object-authz + RLS Low (defense in depth)
Excessive data exposure / mass assignment DTO allow-lists + field authz Low
Privilege escalation via role change Deny-by-default + authorized role changes only Low
Admin function called by member (BFLA) Function-level role checks, deny-by-default Low
Policy bug / misgrant Policy simulation (“prove no public read of /legal”) + CI policy tests Low–medium