Skip to main content
Your progress
0 of 5 complete0%
T4 / M4.7 / L3 OF 4 / Architect LEVEL / 9 min

Per-widget RBAC

Outcome

By the end of this lesson, you will be able to explain the placeholder pattern for gated widgets, identify which widgets each role can see, and explain why a denied widget keeps its slot instead of disappearing.


PrerequisitesM4.1.L1-L6 (RBAC fundamentals) · M4.7.L1-L2 (presets, cloning)
Time9 minutes

1. Concept

Some widgets show things not everybody should see: budgets, recommendations, schedule history.

Permissions apply per widget rather than per dashboard. You build one dashboard, everybody gets the same layout, and each person sees the widgets they are entitled to and a placeholder for the rest.

Terminal window
EXAMPLE: Dashboard with widgets gated on different policies:
WIDGETS ON DASHBOARD REQUIRES
──────────────────────────────────────────────
Cost trend report:view
Top costly resources report:view
Cost saving opportunities recommendation:view
Budget health budget:view
Schedule activity state-history:view
Upcoming actions schedule:view
WHAT EACH ROLE SEES:
Viewer, Editor or Admin (system roles):
All six widgets shown
(every system role holds every *:view policy except
billing:view, so no dashboard widget is gated for them)
Finance Partner (custom role: report:view + budget:view only):
Cost trend, Top costly shown
Cost saving opportunities placeholder
Budget health shown (the custom role grants it)
Schedule activity placeholder
Upcoming actions placeholder

The practical lesson: placeholders appear for custom roles. If you only use the three system roles, every widget renders for everyone, and per-widget RBAC matters the day you write your first narrow custom role.

How it works

Terminal window
DECLARATION:
Each widget declares one required policy in the widget registry.
Example: budget_health.requiredPolicy = "budget:view"
RENDERING:
When the dashboard renders, for each widget:
if user.has(widget.requiredPolicy):
render widget normally (fetch data, display)
else:
render the "no permission" placeholder in the same slot
(the widget component never mounts, so it makes no API call)
SECURITY:
The frontend gating decides what to render
The gateway still enforces: if the user somehow bypasses the
gate and calls the widget's data API, the gateway rejects.
Defense in depth (M4.1.L6).

Widget-to-policy mapping

All 13 widget types and the policy each one needs:

Terminal window
WIDGET REQUIRED POLICY
──────────────────────────────────────────────────────────────────
Key metrics report:view
Cost trend report:view
Cloud spend breakdown report:view
Cost reports report:view
Top costly resources report:view
Showback report:view
Scheduler success rate report:view
Cost saving opportunities recommendation:view
Quick insights recommendation:view
Budget health budget:view
Schedule execution state-history:view
Schedule activity state-history:view
Upcoming actions schedule:view

Five policies cover every widget. A custom role that should read a whole dashboard needs only the policies its widgets list. The same table drives the widget picker: when you edit a dashboard, a widget whose policy you lack is shown disabled in the Add widget drawer.

The “no permission” placeholder

When a widget is gated, the UI renders a short card in the widget’s slot:

Terminal window
┌─────────────────────────────────────────────┐
│ Budget health │
│ │
│ You don't have permission to view this │
│ widget. │
│ │
└─────────────────────────────────────────────┘

The placeholder names the widget and says the user lacks permission. It does not name the missing policy or the user’s role, so the admin works that out from the widget-to-policy table above. It is still much better than an empty widget, which leaves the user confused about why they see nothing.

No hide option

There is no setting to hide a denied widget. A widget the viewer cannot see always keeps its slot and shows the placeholder, so every viewer’s layout matches.

Terminal window
WHY ALWAYS PLACEHOLDER:
Layout is identical for every viewer of the dashboard
Two people discussing "the third widget" mean the same one
Users see what exists and can ask for access to it
No per-role layout to configure, review or get wrong
IF A WIDGET IS IRRELEVANT TO AN AUDIENCE:
Don't rely on hiding: build that audience its own dashboard
without the widget (clone, remove, save; L2)

Why frontend gating + backend enforcement

The placeholder is a frontend decision; the gateway is the security boundary. Both exist for distinct reasons:

Terminal window
FRONTEND PLACEHOLDER:
UX: don't show empty widgets / 403 errors
Performance: don't issue API calls that will fail
Transparency: tell the user something is there
BACKEND GATEWAY:
Security: actually enforce that the user can't fetch the data
Defense in depth: if the frontend has a bug, the gateway still
prevents data leak

A scripted client that ignores the frontend can still attempt to fetch the widget’s data; the gateway rejects with 403. The frontend gate is a UX nicety; the gateway is the security control.

What you control

Terminal window
CUSTOMER CONTROLS:
Role assignment (M4.1.L2-L3): which policies a user holds
Dashboard composition (L2): which widgets a dashboard carries
ZOPNIGHT-MANAGED:
The widget registry declares the required policy per widget
Customers cannot override it (it's a security decision,
not a customization decision)

How ZopNight uses widget RBAC

The widget registry is in code; each entry carries a requiredPolicy. The dashboard renderer checks the viewer’s permission for each slot and renders either the widget or the placeholder. A widget type the frontend does not recognise also gets a placeholder rather than breaking the page, and a widget that throws an error is caught by its own error boundary.


2. Demo

A team dashboard rendered for three different roles:

Terminal window
DASHBOARD: "Platform Eng Daily" (cloned from the FinOps preset)
WIDGETS:
1. Key metrics (report:view)
2. Cost trend (report:view)
3. Cost reports (report:view)
4. Budget health (budget:view)
5. Top costly resources (report:view)
6. Cost saving opportunities (recommendation:view)
7. Schedule activity (state-history:view)
8. Scheduler success rate (report:view)
VIEW A: Admin user:
All 8 widgets shown with data
VIEW B: Viewer (junior, just hired):
All 8 widgets shown with data
Cost saving opportunities is read-only: Viewer can see
recommendations but not act on them
VIEW C: Contractor (custom role: report:view only):
Widgets 1, 2, 3, 5, 8: shown with data
Widget 4 (Budget health): placeholder
Widget 6 (Cost saving opportunities): placeholder
Widget 7 (Schedule activity): placeholder
Layout: identical (each placeholder occupies the same slot)
OBSERVATIONS:
- Same dashboard URL renders differently per role
- Layout consistent (no shifting widgets per role)
- The contractor sees that budget, recommendation and schedule
widgets exist, and can ask for the policies if the work needs them

The placeholder pattern is what makes one dashboard usable for everyone.


3. Hands-on (5 min)

Verify per-widget RBAC on your dashboard:

Terminal window
DASHBOARD reviewed: __________
WIDGETS on it and the policy each needs (use the table above):
□ __________ (policy: __________)
□ __________ (policy: __________)
□ __________ (policy: __________)
CUSTOM ROLES in your org (Settings → Roles):
Role: __________ Missing policies: __________
Widgets that will show a placeholder for it: __________
If you have admin access:
Ask a user with that custom role to open the dashboard
Confirm the placeholders match your prediction
FOR EACH placeholder:
□ Correct (the role should not see it)
□ Wrong (add the policy to the role, or build the audience
its own dashboard without the widget)

If your org uses only the Viewer, Editor and Admin roles, write down which widgets a planned custom role would lose before you create it.


4. Knowledge check

Q1

A user whose custom role lacks budget:view opens a dashboard with the Budget health widget. What do they see?

A. An empty widget area where the panel used to be, with no explanation of why it is gone
B. A raw 403 error message rendered directly inside the widget frame itself, unstyled
C. A placeholder in the same slot, naming the widget and saying they lack permission to view it
D. The widget disappears entirely and the rest of the grid reflows around the gap it leaves

Show answer

Correct: C. The layout stays the same as an admin’s view; only the data is gated. The widget never mounts, so it makes no API call and there is no 403 in the logs. The placeholder does not name the missing policy; the admin reads that from the widget-to-policy table.

Q2

An admin wants a widget to disappear entirely for viewers who cannot see it. What is available?

A. A per-widget Hide setting in the dashboard editor
B. Nothing: denied widgets always show the placeholder
C. A per-role layout override set on the Roles page
D. A hide flag set by support on the org’s settings

Show answer

Correct: B. There is no hide option. A denied widget always keeps its slot and shows the placeholder, so every viewer’s layout matches. If a widget is irrelevant to an audience, build that audience its own dashboard without it.

Q3

The policy a widget needs is decided by:

A. The widget registry, which sets one required policy per widget that customers cannot override
B. A manual setting made per user on each dashboard that they are able to open
C. A per-widget allow-list that is maintained by the organisation’s admins by hand
D. Per-dashboard custom roles, created separately for each dashboard by an administrator

Show answer

Correct: A. ZopNight sets the policy per widget in the registry. Customers control the other two layers: which policies a user holds (role assignment) and which widgets a dashboard carries (composition).


5. Apply

Per-widget RBAC is automatic; no per-dashboard configuration is required to enable it, and there is no per-widget visibility setting to manage. Before you roll out a custom role, check it against the widget-to-policy table so its holders don’t meet a wall of placeholders on the org default.

For multi-role customer demos, show the same dashboard from an Admin’s window and from a narrow custom role’s window: the placeholder pattern is a clear demonstration of the RBAC model in action.



Start with the bill.

Foundations takes about five hours. The first lesson is nine minutes.

Free curriculum. No paywall. 290 lessons across 7 courses, plus an optional 24-lesson beginner course. Browse every course without an account; a free account opens the lessons, saves your progress and opens the exams for three publicly verifiable credentials. Read it on the train, take the exam on a Saturday, list the credential on your résumé Monday.

5h median time to finish Foundations
free account, every course, no paywall
3 certifications, each with a public verifier
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·