A valid login does not grant access to every record
Authentication identifies the caller. Authorization decides whether that caller may perform an action on a particular resource. An API can validate a token correctly and still expose another employee's information if it never checks ownership or organizational scope.
Consider an authenticated request to GET /api/employees/42. The important question is whether the caller may read employee 42. Hiding the link in the interface does not answer that question.
Write the access rule before the endpoint
Describe who may perform each action and under what conditions. For example, an employee may view their own profile, a supervisor may view approved fields for assigned staff, and an HR officer may edit records within their assigned organization.
A role is a useful input, but a role name alone may not express these relationships. Check organization, assignment, record state, and requested operation where the business rule requires them. OWASP's Authorization Cheat Sheet covers these decisions.
Enforce access where the data is read or changed
Use trusted server-side identity information and scope database queries to the caller's permitted records. Do not treat an organization ID supplied in the request as proof of membership. Check permission before returning data or making a change, and deny access when the required policy cannot be evaluated.
Apply the same rule to detail views, search results, exports, attachments, and background jobs. One protected endpoint does not compensate for an unrestricted download route. When returning an error, avoid revealing sensitive resource details.
Check the action and the fields
Read access does not imply permission to approve a request, change a salary, or grant a role. Use explicit input models for editable fields and enforce sensitive actions separately. Otherwise, a request that looks like an ordinary profile update can change a privileged property.
Consider concurrency too. If approval depends on a record still being pending, enforce the permitted state transition when writing the change. An earlier page load is not reliable evidence that the state is still valid.
Test with a second identity
Create test records for two users and, where relevant, two organizations. Verify that a permitted request succeeds, then repeat the operation with another user's ID and with insufficient privileges. Assert both that access is denied and that no data changed.
Include list, export, and write routes in that exercise. Test a removed permission and a changed assignment so access does not persist unexpectedly. These checks are often more useful than adding another successful login test.
Record consequential access decisions without logging sensitive payloads. Audit Logging Without Exposing Sensitive Data explains how to keep that evidence useful.
I build web apps, APIs, and internal systems with security in mind from the start.
All articles · Explore my work