Skip to content

Authorization Specification: Owner-Based RBAC

Authorization Specification: Owner-Based RBAC

Section titled “Authorization Specification: Owner-Based RBAC”

Owner-based Role-Based Access Control (RBAC) for the Graph OLAP Platform. Three hierarchical roles govern access to all API endpoints. Resource ownership is assigned at creation time and is immutable.

Tier: 2 (referenced by all API specs)


RolePurposeSummary
AnalystData usersCreate, query, and analyze graphs. Modify own resources only.
AdminPower usersFull data access across all users. Bulk operations. Schema management.
OpsPlatform operatorsAll Admin capabilities plus system configuration, cluster monitoring, and background jobs.

Analyst < Admin < Ops

Each higher role is a strict superset of the one below it. An Ops user can do everything an Admin can do, and an Admin can do everything an Analyst can do. There is no concept of disjoint permissions between roles.


Complete per-endpoint authorization. “Own” means resource.owner_username == user.username.

EndpointAnalystAdminOps
Mappings GET /api/mappingsList allList allList all
Mappings POST /api/mappingsCreate (owns result)Create (owns result)Create (owns result)
Mappings GET /api/mappings/:idRead anyRead anyRead any
Mappings PUT /api/mappings/:idOwn onlyAnyAny
Mappings DELETE /api/mappings/:idOwn onlyAnyAny
Mappings POST /api/mappings/:id/copyCreate copy (owns result)Create copy (owns result)Create copy (owns result)
Snapshots GET /api/snapshotsList allList allList all
Snapshots POST /api/snapshotsCreate (owns result)Create (owns result)Create (owns result)
Snapshots GET /api/snapshots/:idRead anyRead anyRead any
Snapshots DELETE /api/snapshots/:idOwn onlyAnyAny
Instances GET /api/instancesList allList allList all
Instances POST /api/instancesCreate (owns result)Create (owns result)Create (owns result)
Instances GET /api/instances/:idRead anyRead anyRead any
Instances DELETE /api/instances/:idOwn onlyAnyAny
Instances POST /query (Cypher, read-only)Any instanceAnyAny
Instances algorithm endpointsOwn onlyAnyAny
Favorites * /api/favoritesOwn onlyOwn onlyOwn only
EndpointAnalystAdminOps
GET /api/export-jobsOwn snapshots onlyAllAll

Analyst access is scoped via snapshot ownership: only export jobs for snapshots where snapshot.owner_username == user.username are returned.

EndpointAnalystAdminOps
Schema Admin POST /api/schema/admin/refreshNo accessFull accessFull access
Schema Stats GET /api/schema/statsNo accessFull accessFull access
Bulk Delete DELETE /api/admin/resources/bulkNo accessFull accessFull access
E2E Cleanup DELETE /api/admin/e2e-cleanupNo accessFull accessFull access
EndpointAnalystAdminOps
Config GET/PUT /api/config/*No accessNo accessFull access
Cluster GET /api/cluster/*No accessNo accessFull access
Jobs POST /api/ops/jobs/triggerNo accessNo accessFull access
Jobs GET /api/ops/jobs/statusNo accessNo accessFull access
State GET /api/ops/stateNo accessNo accessFull access
Export Jobs (debug) GET /api/ops/export-jobsNo accessNo accessFull access

Read-Only Endpoints (Any Authenticated User)

Section titled “Read-Only Endpoints (Any Authenticated User)”
EndpointAnalystAdminOps
Schema Browse GET /api/schema/catalogs, /schemas, /tables, /columnsFull accessFull accessFull access
Schema Search GET /api/schema/search/*Full accessFull accessFull access

  1. Assignment. The user who creates a resource owns it. The owner_username is set from the X-Username header at creation time.
  2. Immutable. Ownership cannot be transferred after creation.
  3. No ACLs. There is no resource-level sharing or access control list. Visibility follows the role hierarchy.
  4. Copy creates new ownership. Copying a mapping (POST /api/mappings/:id/copy) creates a new resource owned by the caller, not the original owner.
  5. Storage. The owner_username column is indexed on every resource table (mappings, snapshots, instances).
  6. Cypher queries are not gated by ownership. The wrapper’s /query endpoint is intentionally unauthenticated at the wrapper level. Any authenticated user can execute read-only Cypher against any instance they can reach. Mutating Cypher keywords (CREATE, SET, DELETE, MERGE, REMOVE, DROP) are rejected at the endpoint, so this is a read-catalogue model — consistent with the “Read any” rule for instance metadata. Algorithm execution, by contrast, is owner-gated via require_algorithm_permission/api/internal/instances/:slug/authorize on the control plane.

Authorization is enforced at two layers:

Router functions check the user’s role from X-User-Role before any business logic executes. Requests from users with insufficient roles are rejected immediately with 403 Forbidden.

# Ops-only endpoints
def require_ops_role(user: CurrentUser) -> None:
if user.role != "ops":
raise HTTPException(status_code=403, detail="Requires ops role")
# Admin-or-above endpoints
def require_admin_role(user: CurrentUser) -> None:
if user.role not in ("admin", "ops"):
raise HTTPException(status_code=403, detail="Requires admin role")

For data resource mutations (update, delete), the service layer checks ownership after loading the resource. Admin and Ops users bypass the ownership check.

# Analyst can only modify own resources; Admin/Ops can modify any
if user.role == "analyst" and resource.owner_username != user.username:
raise HTTPException(status_code=403, detail="Only owner or admin can modify this resource")

Both layers must pass for a request to succeed.


StatusConditionResponse
401 UnauthorizedMissing or invalid authentication token{"error": {"code": "UNAUTHORIZED", "message": "Authentication required"}}
403 ForbiddenUser’s role is below the endpoint minimum{"error": {"code": "FORBIDDEN", "message": "Requires admin role"}}
403 ForbiddenAnalyst attempting to modify another user’s resource{"error": {"code": "PERMISSION_DENIED", "message": "Only owner or admin can update this mapping", "details": {"owner_username": "...", "your_role": "analyst"}}}

DocumentRelevance
api.common.spec.mdAuthentication middleware, X-Username / X-User-Role headers
api.admin-ops.spec.mdAdmin and Ops endpoint definitions
api.mappings.spec.mdMapping ownership and 403 responses
api.instances.spec.mdInstance ownership
api.snapshots.spec.mdSnapshot ownership
ADR-084Dual authentication paths
ADR-085JWT extraction middleware