3 Frontend RBAC Quiz: Would Your Permission Check Pass?
Answers to the three questions I left hanging in my last post.
I’ve got answers to the 3 questions from my last post. In that post, I wrote about 3 ways FE can handle authorization
- Static routing
- Server-driven UI
- A granular permission array (instead of roles)
All three are different, but they share one root idea
FE isn’t about security. It’s about UX. Every decision still depends on the server.
Most apps run just fine on this idea. But the trouble starts once real users and real data pile up.
So I left 3 questions at the end of that post. Now I’m back to actually dig into them.
A user is filling in the third field of a form. Meanwhile, the admin quietly revokes their access.
This person has no idea yet.
The frontend doesn’t decide who’s authorized. It’s just a mirror of the server’s decision.
These three questions are really just one, in disguise.
When the mirror shakes. When the mirror breaks. Can you still stand up straight? Haha.

The frontend mirrors the server’s permission decisions.
Q1. What if permission gets revoked mid-action?
The user keeps typing. The admin has already pulled their access. The server won’t save it. That’s the server’s job.
The real problem comes next. The screen just keeps smiling, like nothing happened.
How do you get a real-time update?
You don’t want to be knocking on the server the whole time.
This is where SSE (Server-Sent Events) comes in.
All you really need is one signal: “Something changed.” You don’t need the full data, just the alert.
So… what if that signal gets lost while your connection drops? No worries.
You just send the ID of the last signal you got, and the server fills in the rest.
Q2. What do you trust when the network drops?
When you’re offline, you can’t just ask the server again.
So… should you trust the last permission you saw? Trusting it feels risky. What if it’s already outdated?
The answer is optimistic UI.
You trust the last known permission. Let the user keep working, and queue up whatever they do.
Why is this safe?
Because you can check everything again once you’re back online.
The permission you’re trusting isn’t a real decision. It’s just a temporary kindness.
It’s fine if it’s stale, because the client was never the one making the final call anyway.
So where does the unsynced work go?
Throwing it away is the easy answer. It’s also the wrong one.

An outbox keeps work waiting until it can be sent.
Think of a mailbox. You don’t throw away a letter just because the post office is closed. You drop it in, and it goes out once the office opens again.
Same idea here. You stack the actions in an outbox and send them out in order once you’re back online.
pending → syncing → (synced | rejected)
Q3. What about “I can only edit my own posts”?
This one’s the sneaky trap.
edit:posts tells you the user can edit posts.
It doesn’t tell you whether they can edit this post.
So the check quietly turns into
const canEdit = can('edit:posts') && post.authorId === currentUser.id;
Looks fine at first. The problem is, this one line gets copy-pasted across every component.
That’s the mirror trying to make its own decisions.
The moment FE tries to reimplement the rule, FE has to be updated every time the policy changes.
So instead of shipping the rule, ship the decision.
The server calculates “Can this user do this?” per resource and sends it down with the data
{
"id": "post_123",
"title": "…",
"_permissions": { "canEdit": true, "canDelete": false }
}
// FE just reads the decision
const canEdit = post._permissions.canEdit;
Now, even if the policy changes, your FE code doesn’t change a single line. The server just sends a different value.
(Quick tip: if you’re rendering a list of posts, batch these checks instead of asking one by one.)
Yeah, this value can go stale too. But that’s not a new problem.
The same two answers from Q1 and Q2 apply here
catch the signal and re-check, or trust it optimistically and re-verify later.
So, one rule to rule them all
All three questions really fold into one.
- Permission changes in real time → catch the signal, ask again, but don’t wreck the user’s work.
- The network drops → trust the last permission for a bit, then double-check with the server once you’re back.
- Permission depends on the resource → don’t copy the rule over, just render the decision.
A mirror doesn’t make up answers. It just reflects.




Comments
Comments require JavaScript. The article remains available without it.