← Dev log
EduQate·auth & security·2026-07-18

Every customer could apply, and every one hit a wall

Testing as staff never hit it: as a customer, Apply Now threw a 403 from an admin-only route plus three 'no active form found' 404s at once.

Only visible by using it

Invisible to a code read. Found by being the real user, on a real device, at a real width.

Found it only because I stopped testing as an admin and logged in as a customer. Clicking Apply Now threw four stacked error toasts at once: a 403 and three "no active form found" 404s. The admin side never calls this path, so testing as staff would never surface it.

The 403 came from the intake-cycle list, which the apply flow calls to check for an open intake. That route is admin-only by design, returns internal fields, and is guarded by organisation-ownership scoping that means nothing for a customer. So it's not a wrong role list, it's an endpoint that flow was never meant to call.

Nothing here logs, 500s or pages anyone. It just quietly turns the single most important action in the product into a button that always fails, for every customer, on every organisation, until someone clicks it with the console open. It could have shipped exactly like that.

Fixed with a narrow public endpoint that lists only open intakes, filtered server-side and returning only what an applicant needs, without touching the admin endpoint's guards — adding to its @Roles list wouldn't have worked anyway, since the ownership guard would still reject a customer with no organisation scope.

The general version: an endpoint's authorization can be entirely correct for the role it was built for and still be the wrong door for a different caller. "Does this user have permission" and "should this user be knocking here at all" are separate questions, and testing only as staff answers one of them.