Advanced Row-Level Security
Row-level security gives you precise control over which rows each user can access. This guide walks through advanced row-level security features and practical examples: passing multiple values, numeric and date ranges, handling multiple security groups and datasets in a single dashboard, plus nested Boolean logic. Follow these patterns to implement flexible, secure row filtering in your dashboards.
Advanced Row-Level Security Tutorial
The following tutorial video shows how to add advanced features and capabilities for configuring row-level security with datasets.
Tags: Embedding, RLS, Authorization
row-level security Validation Types: a quick overview
row-level security supports several validation types. They are not one-size-fits-all. Some validations are valid only for numeric data, some only for string data, and some support dates. Validation type choice determines the shape of the value you send. For example:
equal: useful for single values or an array of allowed values not equal: behaves like a not-in list when passed multiple entries range: used for numeric ranges and expressed as an object with comparison properties date-specific declarations: use the group_value property to constrain by year, quarter, month, day, hour, minute, or second Always match your validation type to the column data type you are securing. Date-specific options like group_value only work with date or datetime columns.
Best practice: keep row-level security configuration on the backend
Define and sign row-level security permission blocks in a backend service before sending them to the client. This ensures permission declarations are securely encrypted and not exposed to end users. A common approach is a Node.js backend that builds the row-level security object, signs it, and returns only the signed token to the frontend.
Passing multiple values with equal
If you want to allow multiple specific values for a column, use the equal validation type with a values array. The values property is an array of primitives (strings or numbers). When you pass more than one value, equal behaves like an IN list.
Example intent: allow product IDs 100, 200, and 300. The values array contains those product IDs. The result: only rows whose product ID is in that list are accessible.
Numeric ranges with range validation
When you need a contiguous numeric range, use validationType equal to range and set the value property to an object that uses comparison keys. Common keys are:
gtefor greater-than-or-equal-toltefor less-than-or-equal-to
Example: limit product IDs to the 300 range by using value:
{ "gte": 300, "lte": 399 }.
That configuration restricts access to product IDs from 300 through 399 inclusive.
Date ranges and group_value
To filter dates by calendar granularity, define an row-level security field on a date column and use group_value together with the value. The group_value property lets you constrain the date by units such as year, quarter, month, week, day, hour, minute, or second.
Example: restrict the modified date of product inventory to the year 2025. Use validationType equal, set group_value to year, and set value to 2025. You will only see rows whose modified date falls within that year. You can reduce granularity to quarter, month, week, and so on, to suit your needs.
Multiple security groups on the same dataset
You can add multiple row-level security fields on the same dataset. For instance, you might have one security group on product ID and another on modified date. By default, multiple security groups on the same dataset are combined with AND logic, which is the safest default for security.
Default behavior example: allow any product ID but require modified date to be in 2025. The default AND ensures both conditions apply to rows from that dataset unless you explicitly change the operator.
Multiple datasets referenced in a single dashboard A dashboard can reference multiple datasets and each dataset can have its own row-level security configuration. Add separate record permissions blocks for each dataset you want to secure.
Optimizations to Avoid Duplication
If several datasets use the same set of row-level security field names and same definitions (for example, tenant-based filtering using the same column), you can comma delimit the dataset IDs in a single record_permissions block to apply the same security to multiple datasets. If every dataset referenced in the dashboard has the exact same number and type of row-level security fields defined, you can use a wildcard dataset ID represented by star to apply the same block to all datasets. Use this only when all datasets truly share the identical row-level security schema. Example: add a new row-level security field on the country region code for an entirely different dataset, then add a separate permission block for that dataset with its datasetId and record_permissions. Test by refreshing the dashboard and confirming charts sourced from that dataset reflect the restriction, for example limiting to US only.
Nested Boolean logic: operator and hierarchical rules
The default Boolean operator between multiple record permissions within a dataset is AND. You can change that behavior by adding an operator property with value or to apply OR logic between the listed security groups for that dataset.
Beyond simple AND and OR, hierarchical nested Boolean logic is supported. To build nested conditions, create multiple objects in the top-level record_permissions array. Each top-level object can contain its own record_permissions array and operator. This lets you construct logical groupings and precedence similar to parentheses in a Boolean expression.
Reading a nested example
First child: product ID equals 764
Second child: an inner group using operator and that requires product ID equals 325 and modified date group_value year equals 2025
Interpretation: product ID must be 764, OR product ID must be 325 and the modification date must be in 2025.
This structure lets you express complex conditions, for example allowing one product unconditionally while requiring additional constraints on another product ID.
Wildcards and additional advanced features
Record-level security also supports wildcards for pattern matching in string fields and other advanced validation options. Wildcards can be useful for tenant or role patterns, but be sure to use them with care to avoid unintentionally granting broader access than intended.
Practical testing steps
- Define the row-level security fields on the dataset columns you want to secure (product ID, modified date, country code, and so on).
- Build the permission block in your backend service, keeping values encrypted or signed before returning to the client.
- Restart your backend service so the new permission payload is served.
- Refresh the front-end dashboard and verify filters and chart data reflect the row-level security rules. Inspect available filter selections for constrained fields to confirm the values are limited as expected.
Limits, performance, and data source considerations
Each security group translates into terms in a where clause. For managed datasets the queries often target Elasticsearch; for live connect datasets the queries run against the live data source. There are practical limits on the number of nested terms you can include in a single where clause, but those limits typically number in the tens of thousands. If you expect extremely large numbers of terms or highly nested Boolean trees, test performance and consult platform limits before rolling into production.
Summary and recommendations
- Choose the correct validation type for the data column type you are securing.
- Use arrays with equal to pass multiple allowed values and range with gte/lte for numeric ranges.
- Use group_value for date granularity constraints like year, quarter, month, and so on.
- When multiple datasets share the same row-level security schema, use comma delimited dataset IDs or a wildcard to reduce duplication, but only if they truly match.
- Default Boolean logic is AND. Use operator to set OR at a given level and use nested record_permissions blocks to compose grouped Boolean logic.
- Keep row-level security generation and signing on the backend to protect permission declarations, and validate behavior by restarting services and testing the frontend.
Tip: Start with simple row-level security rules and expand to ranges and nested logic only after confirming behavior and performance for your datasets.