HR Salary App: Screen Roles Aren't Enough
An internal HR compensation app has 850 employees, 30 HR staff, and 6 executives. It uses OutSystems roles: Employee, HR, Executive, and Admin. Screens are protected with screen roles, and the UI hides the salary field for Employee role by placing it in an If widget. A recent audit found that an employee used browser developer tools to call the exposed REST API that backs the salary screen and retrieved 12 colleagues' salaries. The API method has Authentication enabled but no role check; it accepts an employee ID from the request. The entity has CRUD permissions set for HR and Admin, but the API runs with the caller's identity. The audit also found that HR staff can edit their own salary because the edit action only checks IsHR and not whether the record belongs to the caller. The HR director wants a fix in two sprints and asks whether hiding the field better is sufficient.
1. Why did the REST call succeed despite the screen role and hidden field? What authorization checks are missing?
Read the worked answer
The screen role only controls whether the screen can render; the If widget only changes what the browser displays. The exposed REST method is a separate entry point. It has authentication, so the caller is identified, but it has no role check and trusts the employee ID in the request. That is a missing function-level check and a missing object-level check. Entity CRUD permissions do not fix this because they govern entity operations for roles, not whether this caller may request this particular employee's salary through this method. The server must deny by default: verify the caller has a role that permits salary viewing, then verify the requested employee ID is either the caller's own record or within the caller's authorized scope, such as HR business unit. Do not fetch first and filter in the browser.
2. Design the authorization model for viewing and editing salary records, including row-level rules and audit.
Read the worked answer
Separate read and write permissions. Employee: read own record only. HR: read records for assigned business units, but not edit own salary. Executive: read aggregate or all records as required, no edit. Admin: manage roles and configuration, not salary data. Implement checks in server actions, not screens: get caller identity from the session, apply scope filters in the query, and for edits load the target record and reject if target is the caller or outside scope. Use distinct server actions for self-view, HR-view, and edit so one API cannot be reused with a mode flag. Audit every salary read and edit with caller, target, timestamp, action, and reason; store audit immutably. Add negative tests: employee A requests employee B, HR edits self, HR requests outside unit.
3. The HR director asks whether hiding the field better is sufficient. How do you respond?
Read the worked answer
No. Client-side hiding is user-interface hygiene, not access control. Any value sent to the browser can be read in the network response, the DOM, or the client-side model, and any endpoint can be called directly. The correct fix is to not send salary data to unauthorized callers at all. The screen preparation should check the role before loading salary, and the server action should return only permitted fields. Hidden fields and disabled buttons can remain as usability cues, but they must never be the only barrier. Test by calling the endpoint as an Employee with another employee's ID and by inspecting the response payload; the response should contain no salary field.