Row-Level Security for Embedding
Row-level security (RLS) restricts which rows each user can see when they query a shared dataset. In embedded analytics, it's the mechanism that ensures tenant A never sees tenant B's data – even though both tenants view the same dashboard, running queries against the same tables.
RLS operates at the data layer. Every query that reaches the database gets an additional filter injected based on the user's identity and attributes. The user never sees the filter. They can't remove it. It applies before results are returned, regardless of what the dashboard displays.
Why dashboard filters aren't enough
A common misconception: "We filter by tenant in the dashboard, so the data is secure." Dashboard-level filters are user-facing controls. They can be modified, removed, or bypassed – depending on how the embedded component is configured. A user who inspects network requests might see the unfiltered API call. A misconfigured embed might expose the filter selector, letting users choose a different tenant.
Dashboard filters are presentation logic. RLS is access control. The difference is whether a determined or curious user can see data they shouldn't. With dashboard filters alone, the answer is often yes. With RLS, the database itself enforces the boundary.
How RLS works in practice
The mechanics are consistent across most BI tools that support embedded RLS:
User attributes arrive via JWT. The host application generates a JWT token containing claims about the user – at minimum, a tenant identifier. Often also a role, region, or department.
The BI tool maps attributes to filter rules. A data model or policy definition specifies: "When querying the
orderstable, addWHERE tenant_id = {user.tenant_id}." This mapping is defined once and applies to every query against that table.Filters inject at query time. When the BI tool generates SQL, it appends the RLS condition to every relevant query. The user sees "their" data. The database never returns rows outside the filter boundary.
Filters are immutable. The end user has no ability to modify, override, or inspect the RLS filter. It operates below the dashboard layer, in the query generation step.
Implementation patterns
RLS implementations fall into a few common patterns, each suited to different data models:
Single-column tenant filter. The simplest and most common. Every table has a tenant_id column. The RLS rule filters on it. This works well for simple multi-tenant schemas where every row belongs to exactly one tenant.
Role-based policy tables. A separate table maps roles to data access rules. A "regional manager" role might grant access to rows where region IN ('us-west', 'us-east'). The BI tool joins the user's role against the policy table to determine visible rows. This pattern handles complex hierarchical access models.
Attribute-based rules. Multiple user attributes combine to define access. A user with department = 'sales' and region = 'emea' sees rows matching both conditions. The rules can be additive (AND logic) or permissive (OR logic) depending on the security model.
Row-ownership patterns. Some datasets have a created_by or owner_id column. RLS filters to rows the user owns – useful for personal data views like "my deals" or "my support tickets."
The choice depends on your data model and access requirements. Most production implementations combine patterns – tenant filtering as the base layer, with role-based or attribute-based rules layered on top.
Why RLS is non-negotiable for customer-facing analytics
Data leakage in an embedded analytics context is a trust-destroying event. If one customer sees another customer's revenue numbers, support tickets, or user activity, the consequences go beyond a bug report. It's a security incident. It erodes trust in your product's data handling. In regulated industries, it's a compliance violation with material consequences.
RLS is the control that prevents this class of failure. It moves the access boundary from application logic – which can have bugs, misconfigurations, and edge cases – to the query layer, where enforcement is systematic.
The implementation cost is low relative to the risk. Define the tenant column. Map it to the JWT claim. Apply the policy to every table that contains tenant-scoped data. Test it by loading the dashboard as different tenants and verifying that each sees only their own rows.
For the full picture of how RLS connects to the broader embedded analytics security model, see JWT embedding for the authentication layer and multi-tenant analytics for the architectural patterns that RLS supports.
The Holistics Perspective
Holistics enforces row-level security through its Row-Level Permissions (RLP) system. Security rules are defined in the data model and applied at query time based on user attributes from the JWT token. These rules cannot be bypassed from the dashboard layer, ensuring tenant isolation for embedded analytics.
See how Holistics approaches this →