Stop 12 · AuthenticationTopics · 9/10

Role Based Access

Part of the Frontend Developer Roadmap

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.

The jaadu holds one key in a corridor of three coloured doors, while a student and a teacher try other doors.

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

Editor
API route
can()

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

ts
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

~40 min

Quick check

A logged-in editor calls DELETE /api/posts/5, but only admins may delete. What should the server return?

Go deeper

  1. 1Model a simple role field on your user object and gate one feature by it.
  2. 2Build a reusable role-guard wrapper component.
  3. 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.

Download
InsideEdge