Enravo Core's RBAC system maps roles directly to abilities — no intermediate permission layers. Abilities auto-register from schemas and controllers. Wildcard matching (module/*) supported. Administrator bypass is the single source of truth.
Abilities follow the format enravo/{module}/{action}. They're auto-registered from three sources: schema definitions (view/create/edit/delete per schema), controller routesMeta, and explicit module registration. The Registry batches all registrations into a single DB sync — reducing ~60 queries to 0-2.
1// Abilities auto-register from 3 sources:2
3// 1. From schemas (auto)4"enravo/sube.branch/view" // → GET list + GET single5"enravo/sube.branch/create" // → POST6"enravo/sube.branch/edit" // → PUT/PATCH7"enravo/sube.branch/delete" // → DELETE8
9// 2. From controller routesMeta (auto)10"enravo/core/install-challenge"11"enravo/auth/login"12"enravo/account/me"13
14// 3. Explicit registration (modules)15Registry.register({16 name: "enravo/pay/process-payment",17 label: "Process Payment",18 module: "pay",19 policyKey: "user.write",20 allowGuest: false,21});From user to decision — no intermediate layers, no cache staleness, evaluated on every request.
Authenticated User
JWT validated, user_id extracted from claims
WordPress Role
User's WP role fetched — direct mapping, no intermediate Enravo role
Role Abilities
wp_enravo_role_abilities queried — all abilities for this WP role
Ability Match
Endpoint's required ability matched against user's abilities (including wildcards)
Client Role Check
User's role matched against client's allowed login_roles
Allow / Deny
Binary — no partial access. Full audit log on both outcomes
Authenticated User
JWT validated, user_id extracted from claims
WordPress Role
User's WP role fetched — direct mapping, no intermediate Enravo role
Role Abilities
wp_enravo_role_abilities queried — all abilities for this WP role
Ability Match
Endpoint's required ability matched against user's abilities (including wildcards)
Client Role Check
User's role matched against client's allowed login_roles
Allow / Deny
Binary — no partial access. Full audit log on both outcomes
40+ abilities, wildcard matching, role-based restrictions. Every permission enforced at the endpoint level.
| Ability | administrator | moderator | customer | guest |
|---|---|---|---|---|
| products.* | ||||
| orders.create | ||||
| orders.list | own | |||
| users.manage | ||||
| config.update | ||||
| reports.view | ||||
| products.read | ||||
| profile.update | own |
From ability format to field-level permissions — every layer enforced.
enravo/{module}/{action} — enforced at registration. Must start with 'enravo/' prefix. 3+ path segments required. Invalid formats rejected silently.
All abilities collected in memory during boot. Single DB batch on rest_api_init. Hash comparison detects changes — only writes when abilities actually changed.
Each API client defines which roles can log in. Mobile consumer app: only 'customer'. Admin app: only 'administrator'. Same user, different access per client.
Single source of truth in Permissions class. Administrator role has all abilities — not via wildcard, but via explicit check. No separate bypass flag. No security holes.
Admin screen lists all abilities grouped by module. Toggle abilities per role. show_in_role_manager flag controls visibility — internal abilities hidden from admin UI.
SchemaPipeline enforces field-level permissions: readable (who sees it), writable (who edits it, per create/update). Separate from endpoint abilities — both must pass.