In short
Being logged in is one question. Being allowed to delete every post is another. Role based access control (RBAC) decides what each kind of user can do once they're inside.
Restricting features or pages based on a user's role (admin, editor, viewer) rather than just whether they're logged in at all.

Think of it like this
Who can do what in college
Students can view marks. Teachers can enter marks. Only the HOD can change them after submission. Everyone has a valid ID card, but the role on it decides which register they can write in.
Watch it happen
An editor tries to delete a post
DELETE /api/posts/5
1/5The editor's browser sends a delete request, maybe from DevTools.
The big ideas
What you need to know
Roles group permissions
Give users a role like admin, editor or viewer. Each role maps to a list of things it may do.
Check permissions, not role names
Ask 'can this user delete posts?' instead of 'is this user admin?'. Adding a new role later becomes easy.
The server has the final word
Hide buttons in the UI for comfort, but the API must check the permission before doing anything.
Roles change
If a role is baked into a long-lived token, a demoted user keeps powers until it expires. Keep tokens short or re-check the database.
See it in code
Walk through the code
1type Role = "viewer" | "editor" | "admin";2type Action = "post:read" | "post:edit" | "post:delete";3 4const PERMISSIONS: Record<Role, Action[]> = {5 viewer: ["post:read"],6 editor: ["post:read", "post:edit"],7 admin: ["post:read", "post:edit", "post:delete"],8};9 10export function can(role: Role, action: Action) {11 return PERMISSIONS[role].includes(action);12}13 14// In an API route, after verifying the session:15if (!can(user.role, "post:delete")) return new Response("Forbidden", { status: 403 });1/4Types list every role and action, so a typo like post:delte won't compile.
Use the same can() function on the client (to hide buttons) and the server (to enforce). TypeScript stops you from typo-ing an action name.
Save yourself the pain
Common mistakes
Oops
Sprinkling if (user.role === "admin") checks all over the code.
Do this instead
Keep one permission map and one can() helper. Changing who can do what becomes a one-line edit.
Oops
Returning 401 when a logged-in user lacks permission.
Do this instead
401 means 'not logged in'. Use 403 Forbidden when you know who they are but they aren't allowed.
Your mission
Build a three-role blog
Quick check
A logged-in editor calls DELETE /api/posts/5, but only admins may delete. What should the server return?
Go deeper
- 1Model a simple role field on your user object and gate one feature by it.
- 2Build a reusable role-guard wrapper component.
- 3Remember to also enforce role checks on the backend, not just hide UI on the frontend.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.