Implement Role-Aware User Information Views
IntuitStaff Software Engineer · Technical ScreenLast updated
Implement a field-level access control engine that redacts sensitive attributes from user profile records based on viewer permissions, context, and ownership relationships.
Problem Statement
In multi-tenant financial and HR platforms, user profile data contains varying levels of sensitivity (e.g., public display names, internal email addresses, and restricted data such as compensation or tax identifiers).
Implement a role-aware profile sanitizer ProfileSanitizer that filters user profile records before returning them to clients. The sanitizer must enforce field-level permissions based on the viewer's role, the viewer's relationship to the target user (horizontal access control), and the query context ("detail" vs "list").
Access Rules
- Roles: A user can have one of three roles:
"ADMIN","MANAGER", or"EMPLOYEE". - Field Policies:
id,name: Visible to everyone in all contexts.department: Visible to everyone in all contexts.email: Visible toADMIN, the user themselves (SELF), or any colleague in the same department.phone: Visible toADMIN, the user's direct manager (MANAGER), orSELF.salary,ssn: Visible only toADMIN, and to the user's direct manager only when viewing in"detail"context. A user cannot view their ownssnvia this endpoint.
- Context Sensitivity:
- In
"list"context,salaryandssnare always excluded, even forADMIN.
- In
Interface
class ProfileSanitizer:
def __init__(self):
pass
def sanitize_profile(
self,
viewer: dict,
target_user: dict,
context: str = "detail"
) -> dict:
"""
Returns a new dictionary containing only the fields the viewer
is authorized to see for target_user under the given context.
"""
pass
Input Format
viewer:{"id": str, "role": str, "department": str}target_user:{"id": str, "name": str, "department": str, "manager_id": str, "email": str, "phone": str, "salary": int, "ssn": str}context: Either"detail"or"list".
Example 1
viewer = {"id": "u2", "role": "EMPLOYEE", "department": "Engineering"}
target = {
"id": "u1",
"name": "Alice",
"department": "Engineering",
"manager_id": "u3",
"email": "[email protected]",
"phone": "555-0100",
"salary": 120000,
"ssn": "000-00-0000"
}
sanitizer = ProfileSanitizer()
result = sanitizer.sanitize_profile(viewer, target, context="detail")
Output:
{
"id": "u1",
"name": "Alice",
"department": "Engineering",
"email": "[email protected]"
}
Explanation: The viewer is in the same department (Engineering), so email is allowed. However, the viewer is not Alice (SELF), not Alice's manager, and not an ADMIN, so phone, salary, and ssn are stripped.
Constraints
viewerandtarget_userdictionaries will always contain their required schema keys.contextis guaranteed to be either"detail"or"list".- The function must return a new dictionary without mutating
target_user.
Hints
Hint 1
Determine the viewer-to-target relationship first (is_self, is_admin, is_manager, is_same_dept) before evaluating individual field predicates.
Hint 2
Decouple field visibility rules into a declarative policy map rather than using nested if-else blocks.
Hint 3
Remember that context rules can override role permissions (for instance, list context always suppressing salary and ssn regardless of viewer role).
Follow-up questions
- How would you optimize this sanitizer when transforming a paginated list of 1,000 target users for the same viewer?
- How would you integrate this authorization logic with GraphQL field resolvers or an ORM without causing N+1 query problems?
- If business requirements demand audit logging whenever restricted fields like SSN are accessed, where and how would you hook that in without coupling audit side-effects to the sanitizer logic?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.