Instructor walkthrough and answer key
From exercises/05-broken-access-control/student at the repository root, run node server.mjs and open http://127.0.0.1:3000. Alex is the fixed demonstration user (student-1). The starter permits both record 101 (Alex) and record 102 (Sam). The server is not failing to identify a user; it is failing to restrict that user's access.
The complete repair in authorize.mjs is:
export function canReadRecord(user, record) {
return record.ownerId === user.id;
}
The server chooses the user and finds the record before calling this function. The browser supplies a requested record ID, not a trusted identity or owner. For this exercise the policy is ownership only; do not add hard-coded record numbers or modify the browser to hide requests.
After saving, Ctrl+C and restart node server.mjs. Request 101: 200 and Alex's record. Request 102: 403, no Sam record contents. Request 999: 404. Request abc: 400. Stop the server and run node checks.mjs from the same folder; it starts and stops its own test server. All checks should pass after repair. A starter failure is intentional, not a reason to modify expected results.
Alternatively, run the untouched reference implementation from the exercise's solution folder. Stop the previous server first. Both apps use the same infrastructure; only the permission function differs.
Expected explanations
- An ID identifies an object. The server must separately decide whether the requester may access it.
- Hiding a button changes a user interface, not what requests the server accepts.
- Testing only denial could reward a broken repair that blocks everyone. Testing allowed access catches that mistake.
- Authentication is supplied as a fixed fictional identity. Students implement authorization, not a real login/session mechanism.
- Random IDs can make guessing harder but do not replace authorization.
Frequent mistakes
Returning false for every record blocks legitimate work. Comparing a record's ID with the user's ID confuses different identifiers. Comparing to the literal string 'user.id' compares against those characters, not a property. Editing a different copy or not restarting leaves the old function running. Returning a truthy non-boolean is not the intended contract: return the boolean comparison.
Avoid claiming this tiny application is production hardened. Real systems need authenticated sessions, appropriate policies, monitoring and many other controls beyond this lesson.