Authorization Overview
Overview
ASCEND implements enterprise-grade authorization with a 6-level role-based access control (RBAC) hierarchy, 23+ granular permissions, separation of duties (SoD) for high-risk operations, and database-enforced multi-tenant isolation via PostgreSQL Row-Level Security (RLS).
Why It Matters
Authorization ensures the right people have access to the right resources:
- Least Privilege: Users only have permissions necessary for their role
- Separation of Duties: Critical operations require multiple approvers
- Multi-Tenant Isolation: Organizations cannot access each other's data
- Audit Compliance: All access decisions are logged and traceable
- Risk-Based Access: High-risk actions require elevated permissions
Architecture
Authorization Flow
+------------------+ +------------------+ +------------------+
| Authenticated | | RBAC Engine | | RLS Enforcement |
| Request | | | | (PostgreSQL) |
+--------+---------+ +--------+---------+ +--------+---------+
| | |
| 1. User Context | |
| (from auth) | |
+----------------------->| |
| | |
| | 2. Check Role Level |
| | |
| | 3. Check Permissions |
| | |
| | 4. Check SoD Rules |
| | |
| | 5. Set RLS Context |
| +----------------------->|
| | |
| | | 6. Enforce
| | | Tenant
| | | Isolation
| | |
| 7. Authorization | |
| Decision | |
|<-----------------------+ |
Authorization Components
| Component | Purpose | Implementation |
|---|---|---|
| RBAC Engine | Role and permission checks | rbac_manager.py |
| RLS Enforcement | Multi-tenant data isolation | PostgreSQL policies |
| SoD Rules | Dual-approval requirements | separation_of_duties dict |
| Permission Decorators | Endpoint protection | @require_permission() |
RBAC Model
6-Level Role Hierarchy
Level 5: EXECUTIVE ─────────────────────────────────────┐
│ │
│ All privileges + critical overrides │
│ │
Level 4: ADMIN ────────────────────────────────┐ │
│ │ │
│ Full system access except overrides │ │
│ │ │
Level 3: MANAGER ───────────────────────────┐ │ │
│ │ │ │
│ Authorization + approve LOW/MEDIUM │ │ │
│ │ │ │
Level 2: POWER ──────────────────────┐ │ │ │
│ │ │ │ │
│ Analytics + alerts + ack │ │ │ │
│ │ │ │ │
Level 1: BASIC ─────────────────┐ │ │ │ │
│ │ │ │ │ │
│ Dashboard view only │ │ │ │ │
│ │ │ │ │ │
Level 0: RESTRICTED ─────────────────┴────┴────┴────┴────┘
│
│ No permissions (suspended users)
│
Role Summary
| Level | Role | Description | Key Permissions |
|---|---|---|---|
| 0 | RESTRICTED | Suspended/probationary | None |
| 1 | BASIC | Standard users | Dashboard view |
| 2 | POWER | Power users | Analytics, alerts, acknowledge |
| 3 | MANAGER | Managers | Authorization, approve LOW/MEDIUM |
| 4 | ADMIN | Administrators | Full access, approve HIGH |
| 5 | EXECUTIVE | Executives | All + critical overrides |
Permission Categories
23+ Granular Permissions
| Category | Permissions | Description |
|---|---|---|
| Dashboard | view, export | Dashboard access |
| Analytics | view, reports, export | Analytics features |
| Alerts | view, acknowledge, correlate, dismiss | Alert management |
| Rules | view, create, modify, delete | Rule configuration |
| Authorization | view_pending, approve_low/medium/high/critical, emergency_override | Action approval |
| Users | view, create, modify, delete, reset_password, manage_roles | User management |
| Audit | view, export, delete | Audit log access |
| System | config, backup, maintenance | System administration |
Separation of Duties (SoD)
Risk-Based Approval Requirements
| Risk Level | Score Range | Required Approvers | Required Roles |
|---|---|---|---|
| Low | 0-49 | 1 | MANAGER+ |
| Medium | 50-69 | 1 | MANAGER+ |
| High | 70-89 | 2 | ADMIN + ADMIN |
| Critical | 90-100 | 2 | EXECUTIVE (different departments) |
SoD Rules
| Rule | Description | Requirements |
|---|---|---|
high_risk_approval | High-risk actions (70-89) | 2 approvers, cannot approve own |
critical_risk_approval | Critical actions (90-100) | 2 EXECUTIVE, different departments |
user_role_changes | Role changes | MANAGER + ADMIN |
emergency_override | Emergency bypass | 2 EXECUTIVE + justification |
SoD Implementation
separation_of_duties = {
"high_risk_approval": {
"description": "High-risk actions require dual approval",
"risk_threshold": 70,
"required_approvers": 2,
"required_levels": [AccessLevel.ADMIN, AccessLevel.EXECUTIVE],
"cannot_approve_own": True
},
"critical_risk_approval": {
"description": "Critical actions require executive + admin approval",
"risk_threshold": 90,
"required_approvers": 2,
"required_levels": [AccessLevel.EXECUTIVE],
"required_different_departments": True,
"cannot_approve_own": True
},
"user_role_changes": {
"description": "User role changes require manager + admin",
"required_approvers": 2,
"required_levels": [AccessLevel.MANAGER, AccessLevel.ADMIN],
"cannot_approve_own": True
},
"emergency_override": {
"description": "Emergency overrides require dual executive approval",
"required_approvers": 2,
"required_levels": [AccessLevel.EXECUTIVE],
"required_justification": True,
"audit_immediately": True
}
}
Row-Level Security (RLS)
Multi-Tenant Isolation
PostgreSQL RLS ensures organizations cannot access each other's data:
-- Enable RLS on table
ALTER TABLE agent_actions ENABLE ROW LEVEL SECURITY;
-- Create isolation policy
CREATE POLICY org_isolation ON agent_actions
FOR ALL
USING (organization_id = current_setting('app.current_organization_id')::integer);
Session Context Setting
# Set RLS context after authentication
db.execute(text(f"SET LOCAL app.current_organization_id = {organization_id}"))
# All subsequent queries automatically filtered by organization_id
agents = db.query(Agent).all() # Only returns agents for current org
Authentication Bootstrap
For authentication lookup (before org is known), ASCEND uses a SECURITY DEFINER function:
-- Bypasses RLS only for authentication lookup
CREATE FUNCTION auth_lookup_api_key(prefix VARCHAR)
RETURNS TABLE(...) AS $$
BEGIN
RETURN QUERY SELECT ... FROM api_keys WHERE key_prefix = prefix;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
Configuration
Environment Variables
# RBAC Configuration
DEFAULT_USER_ROLE=basic
REQUIRE_SOD_FOR_HIGH_RISK=true
SOD_HIGH_RISK_THRESHOLD=70
SOD_CRITICAL_RISK_THRESHOLD=90
# RLS Configuration
ENABLE_RLS=true
RLS_FAIL_OPEN=false # If true, disables RLS on error (NOT RECOMMENDED)
Organization-Level Settings
{
"auth_config": {
"default_role": "basic",
"require_sod": true,
"sod_thresholds": {
"high": 70,
"critical": 90
},
"allowed_roles": ["basic", "power", "manager", "admin"],
"role_approval_required": ["admin", "executive"]
}
}
Usage
Permission Check in Code
from rbac_manager import enterprise_rbac, require_permission, Permission
# Check permission programmatically
if enterprise_rbac.has_permission(user.access_level, Permission.ALERTS_ACKNOWLEDGE):
# User can acknowledge alerts
pass
# Decorator-based check
@require_permission(Permission.RULES_CREATE)
async def create_rule(current_user: dict, rule_data: dict):
# Only users with rules.create permission can access
pass
Risk-Based Approval Check
from rbac_manager import enterprise_rbac
# Check if user can approve risk level
can_approve = enterprise_rbac.can_approve_risk_level(
user_access_level=user.access_level,
risk_score=75 # High risk
)
# Check SoD requirements
sod_requirement = enterprise_rbac.requires_separation_of_duties(
action_type="approval",
risk_score=75
)
if sod_requirement:
# Requires dual approval
required_approvers = sod_requirement["required_approvers"]
FastAPI Dependency
from dependencies_rbac import require_admin_role, require_minimum_level
# Require admin role
@router.post("/users")
async def create_user(
user_data: UserCreate,
current_user: dict = Depends(require_admin_role)
):
pass
# Require minimum access level
@router.get("/reports")
async def get_reports(
current_user: dict = Depends(require_minimum_level(AccessLevel.MANAGER))
):
pass
Fail-Secure Behavior
| Scenario | Response | HTTP Status |
|---|---|---|
| Missing role | Assume RESTRICTED (level 0) | N/A |
| Permission check fails | DENY | 403 |
| Role lookup error | DENY | 403 |
| SoD check fails | Require additional approval | 403 |
| RLS context not set | Return empty results | N/A |
| RLS policy error | FAIL operation | 500 |
Compliance Mapping
| Framework | Control | Implementation |
|---|---|---|
| SOC 2 | CC6.1 | Role-based access, least privilege |
| SOC 2 | CC6.2 | Separation of duties |
| SOC 2 | CC6.3 | Role-based authorization |
| HIPAA | 164.312(a)(1) | Access control, unique user IDs |
| PCI-DSS | Req 7.1 | Need-to-know access |
| PCI-DSS | Req 7.2 | Access control systems |
| NIST 800-53 | AC-2 | Account management |
| NIST 800-53 | AC-3 | Access enforcement |
| NIST 800-53 | AC-5 | Separation of duties |
| NIST 800-53 | AC-6 | Least privilege |
Verification
Check User Permissions
curl -X GET https://api.ascend.io/v1/auth/permissions \
-H "Authorization: Bearer $TOKEN"
# Response
{
"user_id": 123,
"access_level": 4,
"role_name": "Administrator",
"permissions": [
"dashboard.view",
"dashboard.export",
"analytics.view",
"analytics.reports",
"alerts.view",
"alerts.acknowledge",
...
],
"can_approve": {
"low": true,
"medium": true,
"high": true,
"critical": false
},
"requires_sod_for_high_risk": true
}
Test Permission Enforcement
# Try to access admin endpoint without permission
curl -X POST https://api.ascend.io/v1/users \
-H "Authorization: Bearer $BASIC_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email": "new@example.com"}'
# Expected: 403 Forbidden
{
"detail": "Insufficient permissions. Required: users.create"
}
Verify RLS Isolation
# As org 1 user, try to access org 2 data
curl -X GET https://api.ascend.io/v1/agents/999 \
-H "Authorization: Bearer $ORG1_TOKEN"
# Expected: 404 Not Found (RLS prevents access)
{
"detail": "Agent not found"
}
Next Steps
- RBAC Reference - Detailed role hierarchy
- Permissions Reference - All 23+ permissions
- AI Security Overview - AI-specific security controls