Role-based access control
cadence:* permissions, BuiltInRBACProvider, Redis cache, and route dependencies.
Intended audience: Stakeholders, Business analysts, Solution architects, Developers, Testers
Learning outcomes by role
Stakeholders
- Relate roles and permissions to auditability and separation of duties for platform versus org admins.
Business analysts
- Map personas to roles and expected 403 outcomes when permissions are missing.
Solution architects
- Explain Postgres plus Redis caching for RBAC and implications for stale permission windows.
Developers
- Use permission constants, BuiltInRBACProvider, and route dependencies (roles_allowed) consistently.
Testers
- Build matrices of roles versus endpoints using cadence:* strings and wildcard behavior.
Users receive roles; roles carry permission strings (for example cadence:org:read). Handlers and dependencies evaluate those strings before sensitive work. Map personas to roles and expect 403 when a permission is missing; implementation centers on permission constants, BuiltInRBACProvider loading and cache, and HTTP dependencies in authorization middleware.
Summary for stakeholders
Section titled “Summary for stakeholders”- Governance — Permissions are explicit
cadence:*strings attached to roles; platform-wide power is concentrated incadence:system:*capabilities.
Business analysis
Section titled “Business analysis”- Personas — Map product roles (org member, org admin, sys admin) to
cadence:*sets when writing acceptance criteria for 403 versus wrong org. - Audit — Permission changes should trigger cache invalidation expectations in defect reports when behavior lags edits.
Architecture and integration
Section titled “Architecture and integration”Cadence RBAC uses PostgreSQL for roles and assignments and Redis to cache computed permission sets (see BuiltInRBACProvider TTL and authz:perms:* keys). Interactive (JWT) sessions store global_permissions and org_permissions in Redis when the session is created or refreshed. API keys use a flat scope list from the key row, with the riskiest platform permissions removed automatically.
Implementation notes
Section titled “Implementation notes”Permission strings
Section titled “Permission strings”Constants live in cadence.core.authorization.permissions. Examples:
- System:
cadence:system:admin,cadence:system:settings:read, … - Org:
cadence:org:read,cadence:org:orchestrators:write, … - User/chat:
cadence:chat:use,cadence:profile:write, …
SYSTEM_ADMIN (cadence:system:admin) in global_permissions marks a platform superuser (BearerTokenSession.is_sys_admin).
Wildcard expansion — expand_wildcard_permissions and has_permission implement hierarchical checks (see has_permission in the permissions module).
BuiltInRBACProvider
Section titled “BuiltInRBACProvider”BuiltInRBACProvider:
- Loads user → role assignments via
UserRoleRepository.list_for_user. - For each assignment, loads role → permission strings via
RoleRepository.list_permissions_for_role. - Merges global (
org_id is None) vs org-scoped rows whenorg_idis passed toeffective_permissions(user_id, org_id). - Caches merged sets in Redis under
authz:perms:{user_id}:{org_id}for 300 seconds (CACHE_TTL_SECONDS). invalidate_cache(user_id)scans and deletes keys when roles change.
Route enforcement
Section titled “Route enforcement”Depends(roles_allowed(PERM))— User must be logged in and satisfy every listed permission according to authorization middleware (_holds_role/has_permission).Depends(authenticated)— User must be logged in; no extra permission check.require_platform_sys_admin/require_admin— Narrow entry points for platform or admin operations.
Many org-scoped handlers then call org_context from the shared route helpers so the user is a member of the org being touched.
API keys vs interactive sessions
Section titled “API keys vs interactive sessions”sanitize_api_key_flat_scopes removes SYSTEM_ADMIN and system API-key management permissions from key scopes (API_KEY_SESSION_STRIPPED_PERMISSIONS in the permissions module).
Verification and quality
Section titled “Verification and quality”Limitations
Section titled “Limitations”- Cache staleness — Up to 5 minutes before Redis effective-permission cache matches DB after role edits, unless
invalidate_cacheis called on the relevant code paths. - Session snapshot — Interactive JWT sessions store permissions at login/refresh; changing roles in DB does not update Redis until the user refreshes the token or re-authenticates.