View-Level Gating
Visual Alignment, Not Security
Section titled “Visual Alignment, Not Security”Our server-side Express routes are now defensively secured with the requireRole middleware. But the resulting user experience for our MODERATOR users is currently frustrating. They navigate to the Contact Submissions dashboard, click a highly visible “Delete Entry” button… and are immediately slapped with a “403 Forbidden” error screen because the route rejected them.
UI Gating is the practice of hiding controls and navigation elements that a user does not have permission to utilize.
We must conceptually understand that hiding a button using CSS or EJS if/else blocks is fundamentally not security. It is purely user experience alignment. A malicious user can trigger the underlying POST request utilizing an API tool like Postman regardless of whether the button is rendered on screen. The Express middleware serves as the security. The EJS UI gating serves as the UX.
Passing Authorization Context to Views
Section titled “Passing Authorization Context to Views”To conditionally hide interface elements dynamically, the EJS template requires awareness of exactly which capabilities the currently logged-in user possesses. We cleanly achieve this by deploying standard Express res.locals configuration directly inside our primary router endpoint.
// Admin: contacts inbox pagerouter.get("/contacts", async (req, res) => { const contacts = await _contactOps.getAllContactsAdmin();
// 1. Determine explicitly if the user possesses the pure ADMIN role const isAdmin = req.user.role === "ADMIN";
// 2. Attach that specific Boolean directly to the response locals res.locals.canDeleteContacts = isAdmin;
res.render("admin/contacts/index", { contacts });});Applying the Gates in EJS
Section titled “Applying the Gates in EJS”Inside the physical template, we utilize simple condition checks evaluating our explicitly defined target boolean. Moderators will see the submission details and a Read toggle, but only Admins will see the Delete button.
Because we are utilizing client-side JavaScript (fetch()) to handle the deletion action asynchronously rather than a standard HTML form submission, we only need to secure the physical <button> element itself.
<!-- The Action Cluster --><div class="admin-actions"> <!-- Visual Status Pill --> <!-- ... existing Read/Unread radio logic ... -->
<!-- The Delete button renders strictly if the capability resolves to true --> <% if (canDeleteContacts) { %> <button class="btn btn-danger contact-delete">Delete</button> <% } %></div>T.A. Watts Note: Do not repeatedly evaluate complex logic deep within EJS templates (e.g. <% if (user.role === 'ADMIN' || user.role === 'SUPER-ADMIN') { %>). Offload that logic into the server-side router explicitly mapping strict, legible booleans (e.g. canDeleteContacts = true) securely routing it directly into the template.
Public Interface Gating
Section titled “Public Interface Gating”This gating concept isn’t strictly reserved for the administrative backend either! We can deploy conditional rendering directly against our public index.ejs landing page simply by exposing the current req.user downward.
// Public Home Routeapp.get("/", (req, res) => { // We pass the currently active user directly to the home page renderer res.render("index", { user: req.user });});With user implicitly injected into the locals object provided to every EJS template, we can cleanly render targeted navigation.
<h1>Public Home Page</h1>
<% if (locals.user) { %><h2>Welcome back, <%= user.name || user.email %>!</h2><p><a href="/admin/logout">Log Out</a></p><% } else { %><p>You are browsing as a guest.</p><p> <a href="/admin/login">Log In</a> | <a href="/admin/register">Register</a></p><% } %>
<hr />
<!-- ... basic site navigation loop ... -->With our interface intelligently aligned seamlessly with our underlying permissions, we must review the overarching structural pitfalls that typically emerge when deploying RBAC ecosystems.
Extra Bits & Bytes
Section titled “Extra Bits & Bytes”📘 View-Level Gating Infographic (PNG)
⏭ Next: Least Privilege & Pitfalls
Section titled “⏭ Next: Least Privilege & Pitfalls”The UI looks great. Let’s review the cardinal rule of security to ensure it stays that way.