A security review of Salus brought me back to a question that remains after authentication:
Can this user access this specific resource?
Consider this scenario:
- User A creates patient X.
- User B signs in and receives a valid JWT.
- B calls
GET /patients/X.
If the application looks up the patient by patientId alone, B may receive a patient belonging to A. B is authenticated, but is not authorized to access that object. This is Broken Object Level Authorization (BOLA).
Authorization must reach the query
A valid JWT establishes who made the request. The access rule still needs to use that identity to scope the resource lookup:
patientId + currentUser.id → authorized resource
Instead of:
findById(patientId)
the operation could conceptually use:
findByIdAndOwner(patientId, currentUser.id)
The method name is incidental. The access boundary belongs in the rule and the lookup, including reads, updates, and deletes.
What should the API return for someone else's patient?
A 403 Forbidden response can tell B that patient X exists. When even that fact is sensitive, 404 Not Found may be preferable: X is outside the set of resources B is allowed to see.
The choice depends on the API's policy and should be applied consistently. It makes HTTP responses less useful for probing which IDs exist.
Security as testable behavior
The path does not end at login → JWT → middleware. It continues through the operation on each object:
identity → authentication → authorization → ownership → resource access
This is the property that became a Salus security regression test:
User A creates patient X.
User B tries to access X.
Expected result: 404.
The hardening work reproduced this scenario as a failing test (RED): User A creates X, User B receives a valid JWT and tries to access it. Ownership was then introduced, operations were scoped by ownerId, and cross-user access began returning 404 in this context. The regression test now passes (GREEN), alongside JWT verification on patient routes.
TDD and security regression tests protect this behavior as the system evolves.
Security should be verifiable behavior, not just configuration.
Project: Salus on GitHub
Top comments (0)