Role-Based Access Control
Part of the Full Stack Developer Roadmap
In short
Being logged in isn't the same as being allowed. A student can view marks, a teacher can edit them, and only an admin can delete a course. RBAC writes those rules down once.
Restricting actions or resources based on a user's assigned role (admin, editor, viewer) — enforced on the backend, and reflected in what the frontend even shows as an option.

Think of it like this
The hostel keyring
The warden has keys to every room. Mess staff get the kitchen and store room. Students get only their own room. Nobody hands out keys person by person; keys come with the job. RBAC works the same: permissions belong to roles, and users get roles.
Watch it happen
Roles and what they can do
1/5Three roles. Each user is given one or more of them.
The big ideas
What you need to know
Users get roles
Riya is a teacher. You never attach permissions to Riya directly, so changing a role updates everyone who has it.
Roles get permissions
Name permissions as resource:action, like marks:edit. Check permissions in code, not role names.
Check on the server
Hiding a button isn't security. Every protected route must check the permission on the backend.
Deny by default
If a route forgets to declare a permission, refuse the request instead of allowing it.
See it in code
Walk through the code
1const ROLE_PERMISSIONS: Record<string, string[]> = {2 student: ["marks:view"],3 teacher: ["marks:view", "marks:edit"],4 admin: ["marks:view", "marks:edit", "course:create", "course:delete"],5};6 7export function requirePermission(permission: string) {8 return (req: Request, res: Response, next: NextFunction) => {9 const roles: string[] = req.user?.roles ?? [];10 const allowed = roles.some((r) => ROLE_PERMISSIONS[r]?.includes(permission));11 if (!allowed) return res.status(403).json({ error: { code: "FORBIDDEN" } });12 next();13 };14}15 16app.patch("/marks/:id", requireAuth, requirePermission("marks:edit"), updateMarks);1/4Each role maps to a list of permissions. In bigger apps this lives in the database.
requireAuth sets req.user from the session or token. Request, Response and NextFunction are imported from express.
Save yourself the pain
Common mistakes
Oops
Writing if (user.role === 'admin') all over the codebase.
Do this instead
Check permissions like marks:edit instead. Adding a new role then means editing one table, not fifty if statements.
Oops
Only hiding the Delete button for non-admins in the frontend.
Do this instead
Anyone can call the API with curl. The backend route must check the permission too.
Your mission
Lock down three routes
Quick check
A logged-in student calls DELETE /courses/5. Which status should the API return?
Go deeper
- 1Add a role field to your user model and gate one backend route and one frontend UI element by it.
- 2Build a reusable backend middleware and a frontend hook that both check the required role.
- 3Remember: hiding a button on the frontend is not the same as actually restricting the action.
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.