Skip to content

Intermediate · Authentication and authorization · topic 35 of 54 · 30 min

Authorization: who can do what

Explanation

Authorization decides what a logged-in user is allowed to do. Give each user a role with a list of permissions, check ownership so people can only touch their own data, and do these checks on the server for every request. Missing checks, called broken access control, are the most common serious web bug.

Who you are vs what you may do

Authentication answers "who are you?" (login). Authorization answers "are you allowed to do this?" A logged-in customer is authenticated, but they must still not be authorized to refund other people's orders.

Think of it like this: In an office building, the guard at the gate checks your ID card: that is authentication. Inside, your card opens only the doors of your own floor: that is authorization. Being inside the building does not open the server room.

401 or 403?

StatusMeaningExample
401 UnauthorizedNot logged in, or the login is invalidNo session cookie, expired JWT
403 ForbiddenLogged in, but not allowedA customer opens the admin refunds page
404 Not FoundSometimes used instead of 403 to hide that a record existsAnother user's private order

Role-based access control (RBAC)

In RBAC each user has a role, and each role has a list of permissions. A permission is a named action like "product:update". The code asks "does this role have this permission?" instead of checking user names.

Permissioncustomerstaffadmin
product:readyesyesyes
product:updatenoyesyes
order:readown onlyyesyes
order:refundnonoyes
javascript
// Example only: runs on a server with Node.js and Express
const PERMISSIONS = {
  customer: ['product:read', 'order:read'],
  staff: ['product:read', 'product:update', 'order:read'],
  admin: ['product:read', 'product:update', 'order:read', 'order:refund'],
};

function requirePermission(permission) {
  return (req, res, next) => {
    if (!req.user) return res.status(401).json({ error: 'Login required' });
    const allowed = PERMISSIONS[req.user.role] ?? [];
    if (!allowed.includes(permission)) return res.status(403).json({ error: 'Forbidden' });
    next();
  };
}

app.post('/api/orders/:id/refund', requirePermission('order:refund'), refundOrder);
A permission check as middleware: 401 when not logged in, 403 when not allowed.

Ownership checks

Roles are not enough. A customer has "order:read", but only for their own orders. So after loading the record, check that order.userId equals the logged-in user's id. Even better, put the owner in the query itself: SELECT * FROM orders WHERE id = ? AND user_id = ?.

Broken access control and IDOR

IDOR (Insecure Direct Object Reference) is when the server trusts an id from the URL without checking ownership. Broken access control sits at number one in the OWASP Top 10 list of web risks.

output
GET /api/orders/1043   (Asha's own order)          -> 200 OK
GET /api/orders/1044   (Asha changes one number)     -> 200 OK  <- BUG: Ravi's address and phone!

Fixed server:
GET /api/orders/1044   (order belongs to Ravi)       -> 403 Forbidden (or 404)
IDOR: changing an id in the URL must never show someone else's data.
  • Deny by default: if no rule says yes, the answer is no.
  • Least privilege: give each user, staff member and API key only the permissions they need.
  • Check on the server, on every request, for every action, including "read".
  • Log denied attempts; many 403s from one account is a warning sign.
  • Write tests for "user A cannot see user B's data".
Careful: Hiding a button in the app is not security. Anyone can call your API directly with a tool like curl. The server must check every request.
Tip: Bigger apps use policy libraries such as CASL, Casbin or Cerbos, or PostgreSQL row-level security, so the rules live in one place instead of being scattered across handlers.

Watch the lesson

Authorization: who can do what · 1/6

Authorization

Logging in tells us who you are. Authorization decides what you may do.

Prefer a video by a teacher? Find free videos on “rbac authorization broken access control idor explained” on YouTube ↗

In real life: Order details on an e-commerce site

An order page URL looks like /orders/1043. If the backend only checks "is someone logged in?", any customer can change the number and read other people's names, phone numbers and addresses. A correct backend loads order 1043 and checks that its user_id is the logged-in user (or that the user is support staff with the right permission). Everyone else gets 403 or 404. Bugs like this have exposed customer data at real companies, which is why security testers try them first.

Practice (0/3 done)

Task 1 · Code · Javascript

Write can(user, action, resource) that returns true or false. Rules: no user (null) -> false. role "admin" -> everything allowed. role "staff" -> only "product:read", "product:update" and "order:read". role "customer" -> "product:read" always; "order:read" and "order:update" only when resource.ownerId === user.id. Anything else -> false (deny by default).

Task 2 · Code · Javascript

Write handleGetOrder(req, orders) for GET /api/orders/:id. req is { user, params: { id } } where user may be null and id is a string. Return { status, body }: 401 with { error: "Login required" } if there is no user; 404 with { error: "Not found" } if no order has that id; 403 with { error: "Forbidden" } if the order's ownerId is not the user's id and the user is not an admin; otherwise 200 with the order as body.

Task 3 · Practice

Design the roles and permissions for a college library app with students, librarians and an admin. Make a permissions table and list two IDOR risks with how you would block them.

Quick quiz

Question 1

1.A user without a login calls a protected API. Which status fits?

Question 2

2.A logged-in customer tries to open the admin refunds page. Which status fits?

Question 3

3.What is IDOR?

Question 4

4.What does "least privilege" mean?

Question 5

5.The app hides the "Delete" button from customers. Is the delete API now safe?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Login with Google, OTP and passkeys