Fullstack CourseLearn by building
Back to week 4

Topic

Challenge: JWT + RBAC hole

Definition

Role-based access control restricts an authenticated action to identities holding a required role, and a guard hole occurs when a route authorization check is missing, misconfigured, or checks the wrong condition.

In simpler words

Being logged in is not the same as being allowed to do this specific thing. A guard hole is where that second check is missing or wrong.

This challenge reuses the authentication and authorization habits from earlier weeks: the difference between not authenticated and not authorized, and the role guard pattern.

After this you can

  • Distinguish not authenticated from not authorized
  • Spot a route missing a role check it clearly needs
  • Explain why hiding a control in the client is not a real fix

Where role-based access control holes hide

Definition

A route is vulnerable to privilege escalation when it enforces authentication but omits or misapplies the role or ownership check that should limit which authenticated users may perform that action.

In simpler words

The bug is not about who can log in. It is about who can call this specific admin action once logged in.

The most common hole is a destructive or admin-only route, such as delete, role change, or refund, protected only by a global authentication guard, with no role or ownership check at all.

A subtler hole checks a role but compares against the wrong field, or checks it in a way that can be bypassed by a value supplied in the request body.

Challenge lab

Bug report

Any logged-in member can delete other users tickets, not just admins.

What is broken

DELETE /tickets/:id only relies on the global authentication guard; there is no role check and no ownership check comparing the ticket to the current user.

Broken snippet

@Delete(':id')
remove(@Param('id') id: string) {
  return this.ticketsService.remove(id);
}
// Global JwtAuthGuard just confirms some valid user is logged in.

Pass criteria

  • Only admins, or the ticket owner per the product rule, can delete a ticket
  • A member calling this on someone else ticket receives 403, not 204
  • The fix lives in a guard or decorator, not a hidden client-side button

Choose the correct fix

Keep in mind

  • 401 means the caller is not known; 403 means the caller is known but not allowed here.
  • Every destructive or role-sensitive route needs an explicit guard, not only a logged-in check.
  • Hiding a control in the UI is polish, never the security boundary.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥ 80% (enforced by the API) to save progress.

Checking your session…

10 questions · concept 3 · syntax 2 · practical 3 · logic 2

Concept1. Which statement best defines the JWT and RBAC challenge?
Syntax2. Which code-level choice matches the JWT and RBAC challenge?
Practical3. A reviewer spots a bug related to the JWT and RBAC challenge. What is the right fix?
Logic4. Which reasoning correctly explains the JWT and RBAC challenge?
Concept5. Which boundary does correct use of the JWT and RBAC challenge preserve?
Practical6. What is the safest next step when applying the JWT and RBAC challenge?
Syntax7. Which implementation direction matches the rule for the JWT and RBAC challenge?
Logic8. Which consequence follows from applying the JWT and RBAC challenge correctly?
Concept9. Which claim about the JWT and RBAC challenge is true in this Nest + Postgres monorepo?
Practical10. Which team practice best demonstrates the JWT and RBAC challenge?