
Have you ever wanted to build an application where users have different levels of access to information? Whether it’s a social platform where users can control who sees their profiles, a corporate dashboard with role-based visibility, or a multi-tenant SaaS application, implementing a robust visibility system is crucial for both security and user experience.
In this blog, we will explore multiple ways to implement a visibility system in a REST API and React application. We’ll discuss their advantages and disadvantages and determine the best approach based on performance, scalability, and multi-tenant support.
Managing visibility in a modern web application involves handling both backend-level access control and frontend-level UI restrictions.
1.Backend Visibility Control
Approach 1: Role-Based Access Control (RBAC)
RBAC is a widely used method where users are assigned roles, and each role has permissions to access specific resources.
Implementation Example:
- Define roles and permissions in a database table.
- Assign roles to users.
- Use middleware to filter API responses based on roles.
Pros:
- Simple to implement.
- Centralized access control.
Cons:
- Limited flexibility in fine-grained control.
- Requires updates when new roles or permissions are introduced.
Approach 2: Attribute-Based Access Control (ABAC)
ABAC extends RBAC by allowing policies to consider attributes of the user, resource, and environment.
Implementation Example:
- Store user attributes (e.g., department, clearance level) in the database.
- Define rules dynamically.
Pros:
- More granular and flexible.
- Dynamic policy evaluation.
Cons:
- More complex to implement.
- Harder to manage for large-scale applications.
Approach 3: Query-Based Filtering
Instead of blocking requests, the backend filters the data returned based on user permissions.
Managing User-To-User (or any other Resource) Visibility With Table in MSSQL.
For managing which users can see other users in the system, we can create a UserVisibility table in MSSQL.
Schema Definition:
And use it on each API call to determine whether user has visibility on a resource.
To improve performance, we can modify the UserVisibility table to allow a wildcard (*) for cases where a user should see all others. Instead of storing multiple rows for each user-to-user visibility rule, we introduce a special visibleUserId value (e.g., -1 or *) to indicate full visibility.
Performance Benefits:
- Reduced Table Size: Instead of storing thousands of records for users with full visibility, a single row (visibleUserId = *) covers all cases.
- Faster Queries: Instead of performing multiple JOINs or WHERE IN checks, the query can simply check if a * entry exists for the user.
- Efficient Indexing: With fewer records and well-placed indexes, the database query planner can optimize retrieval better.
Also, to improve performance, we can do:
Caching: Store visibility rules in an in-memory cache (e.g., Redis) to avoid frequent database hits.
Partitioning: For multi-tenant architectures, partitioning the UserVisibility table by tenant ID can improve lookup performance.
Materialized Views: Precompute and store frequently accessed visibility relationships to speed up queries.
Pre-filtering at Query Level: Instead of processing visibility rules in loops, we can filter out non-visible records at the database query stage itself, reducing the processing overhead at the application layer.
Implementation Example:
Pros:
- Avoids unauthorized access to data at the source.
- Improves API security.
Cons:
- Filtering large datasets can impact performance.
- Increased complexity when handling hierarchical permissions.
2. Frontend Visibility Control
Approach 1: Role-Based Rendering
The UI conditionally renders components based on the user’s role.
Pros:
- Simple to implement.
- Works well for hiding UI elements from unauthorized users.
Cons:
- Doesn’t prevent API access.
- Can be bypassed with client-side manipulation.
Approach 2: Server-Defined UI Configuration
The backend sends a configuration object defining what UI elements should be displayed.
Example:
Pros:
- Decouples UI logic from frontend.
- Can dynamically change visibility without redeploying the frontend.
Cons:
- Adds complexity to API responses.
- Requires careful frontend implementation.
Approach 3: Client-Side Feature Flags
Feature flags stored in a state management system (e.g., Redux) control UI visibility.
Pros:
- Enables A/B testing and gradual rollouts.
- Useful for feature toggling across tenants.
Cons:
- Flags must be synchronized with backend logic.
- Can be exposed if not secured properly.
3. Comparison of Approaches
4. Common Misconceptions and Security Risks
Misconception 1: Frontend-Based Security is Enough
Many developers assume that hiding UI elements in React is enough to restrict access. However, attackers can easily bypass this by making direct API requests using tools like Postman or browser dev tools.
- Risk: Unauthorized data access.
- Mitigation: Always enforce visibility rules on the backend.
Misconception 2: Relying Solely on Role-Based Access Control (RBAC)
RBAC is useful but lacks flexibility when users need different levels of visibility beyond predefined roles.
- Risk: Overly permissive access can expose sensitive data.
- Mitigation: Use Attribute-Based Access Control (ABAC) or query filtering for fine-grained control.
Misconception 3: Assuming Database Queries Always Enforce Visibility
A common mistake is exposing records that should be hidden due to missing query filters.
- Risk: Data leakage.
- Mitigation: Ensure queries filter results based on user permissions before returning data.
Misconception 4: Storing Visibility Rules in the Frontend
Using client-side feature flags or local storage for visibility settings can be manipulated by attackers.
- Risk: Malicious users can modify the visibility settings to access hidden elements.
- Mitigation: Store visibility rules in the backend and send only necessary data to the client.
Misconception 5: Ignoring API Rate Limiting and Logging
Even with proper visibility controls, APIs can be exploited via brute-force enumeration.
- Risk: Attackers can infer hidden records by probing different IDs.
- Mitigation: Implement rate limiting, audit logs, and anomaly detection.
By carefully designing a visibility system, developers can ensure that users only see what they should, improving both security and user experience.
Have any questions or alternative approaches? Share them in the comments!
Article author: Aleksandar Ćirić
You may also like

Implementing a Visibility System in Your Application
February 27, 2025

Angular Signals: The Game Changer for Reactivity
February 13, 2025

Why CI/CD is Essential for Software Automation and Efficiency
December 24, 2024

How People Management Contributes to a Healthy Organizational Culture
November 14, 2024

Learning by Doing: The Growth Story of our Frontend Juniors
September 3, 2024

The Art of Perfect Placement (3R): Right Talents, Right Projects, Right Timing
August 20, 2024

Streamline your Workflow with Spreadsheet
July 19, 2024

Mastering Business Development in the IT industry: Essential Tips and Tricks
April 10, 2024

From the Code to the Conference
March 7, 2024

My First Salary as the First Step Towards a Career in IT: Testimonials & Advice
December 4, 2023