From 4ce3d4283abb54ae6b21e9052f7d52e876be8cdf Mon Sep 17 00:00:00 2001
From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com>
Date: Tue, 5 May 2026 16:05:16 +0000
Subject: [PATCH] docs: document conditional row-level access and allow_all in
access policies
---
docs-mintlify/docs.json | 6 +
.../data-modeling/data-access-policies.mdx | 11 +-
.../conditional-row-level-access.mdx | 284 ++++++++++++++++++
.../data-modeling/data-access-policies.mdx | 120 +++++++-
4 files changed, 419 insertions(+), 2 deletions(-)
create mode 100644 docs-mintlify/recipes/access-control/conditional-row-level-access.mdx
diff --git a/docs-mintlify/docs.json b/docs-mintlify/docs.json
index ab131e9bacec3..7348d54411761 100644
--- a/docs-mintlify/docs.json
+++ b/docs-mintlify/docs.json
@@ -648,6 +648,12 @@
"recipes/configuration/custom-data-model-per-tenant"
]
},
+ {
+ "group": "Access Control",
+ "pages": [
+ "recipes/access-control/conditional-row-level-access"
+ ]
+ },
{
"group": "Core Data API",
"pages": [
diff --git a/docs-mintlify/docs/data-modeling/data-access-policies.mdx b/docs-mintlify/docs/data-modeling/data-access-policies.mdx
index cf65f076bfa3d..9cd3816bc63f1 100644
--- a/docs-mintlify/docs/data-modeling/data-access-policies.mdx
+++ b/docs-mintlify/docs/data-modeling/data-access-policies.mdx
@@ -492,6 +492,14 @@ view(`orders_view`, {
+### Conditional row-level filters
+
+You can switch which `row_level` filter applies based on the
+[security context][ref-sec-ctx] — for example, to scope a group to its region
+or to let admins bypass row filters with `row_level.allow_all: true`. See the
+[conditional row-level access recipe][ref-recipe-conditional-row-level] for
+worked examples in YAML and JavaScript.
+
### Mandatory filters
You can apply mandatory row-level filters to specific groups to ensure they only see data matching certain criteria:
@@ -621,4 +629,5 @@ cube(`orders`, {
[ref-ref-dap-role]: /reference/data-modeling/data-access-policies#role
[ref-ref-dap-masking]: /reference/data-modeling/data-access-policies#member-masking
[ref-ref-mask-dim]: /reference/data-modeling/dimensions#mask
-[ref-core-data-apis]: /reference/core-data-apis
\ No newline at end of file
+[ref-core-data-apis]: /reference/core-data-apis
+[ref-recipe-conditional-row-level]: /recipes/access-control/conditional-row-level-access
\ No newline at end of file
diff --git a/docs-mintlify/recipes/access-control/conditional-row-level-access.mdx b/docs-mintlify/recipes/access-control/conditional-row-level-access.mdx
new file mode 100644
index 0000000000000..9bf3352bd9a31
--- /dev/null
+++ b/docs-mintlify/recipes/access-control/conditional-row-level-access.mdx
@@ -0,0 +1,284 @@
+---
+title: Conditional row-level access
+description: Switch row-level filters based on the security context, and let an admin policy grant unrestricted row access on top of more restrictive policies.
+---
+
+## Use case
+
+You want different row-level filters to apply to the same group depending on
+who the user is. For example:
+
+- Users in different regional groups should see only rows for their region.
+- Admins should bypass row filters entirely, even when other policies restrict
+the same role.
+
+You can express both patterns with [`access_policy`][ref-ref-dap] by combining
+[`conditions`][ref-ref-dap-conditions], [`row_level.allow_all`][ref-ref-dap-row-level],
+and the [_OR_ semantics across policies][ref-dap-rls] that match the same group.
+
+## Data modeling
+
+### Region-based switching
+
+Define one policy per region, and gate each policy with a `conditions` entry
+that checks the user's [security context][ref-sec-ctx]. Only the policy whose
+condition evaluates to `true` contributes its `row_level` filter to the query —
+the others are skipped.
+
+In the following example, users in the `analyst` group see rows for their
+region: members of the `emea` group are restricted to EMEA orders, and members
+of the `amer` group are restricted to AMER orders.
+
+
+
+```yaml title="YAML"
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ - group: analyst
+ conditions:
+ - if: "{ security_context.groups and 'emea' in security_context.groups }"
+ row_level:
+ filters:
+ - member: region
+ operator: equals
+ values: ["EMEA"]
+
+ - group: analyst
+ conditions:
+ - if: "{ security_context.groups and 'amer' in security_context.groups }"
+ row_level:
+ filters:
+ - member: region
+ operator: equals
+ values: ["AMER"]
+```
+
+```javascript title="JavaScript"
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ group: `analyst`,
+ conditions: [
+ { if: securityContext.groups && securityContext.groups.includes(`emea`) }
+ ],
+ row_level: {
+ filters: [
+ {
+ member: `region`,
+ operator: `equals`,
+ values: [`EMEA`]
+ }
+ ]
+ }
+ },
+ {
+ group: `analyst`,
+ conditions: [
+ { if: securityContext.groups && securityContext.groups.includes(`amer`) }
+ ],
+ row_level: {
+ filters: [
+ {
+ member: `region`,
+ operator: `equals`,
+ values: [`AMER`]
+ }
+ ]
+ }
+ }
+ ]
+})
+```
+
+
+
+In JavaScript, you can also express the same pattern by making `row_level`
+itself a function of `securityContext` and returning different filters
+depending on the caller:
+
+
+
+```yaml title="YAML"
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ - group: analyst
+ conditions:
+ - if: "{ security_context.groups and ('emea' in security_context.groups or 'amer' in security_context.groups) }"
+ row_level:
+ filters:
+ - member: region
+ operator: equals
+ values:
+ - "{ 'EMEA' if 'emea' in security_context.groups else 'AMER' }"
+```
+
+```javascript title="JavaScript"
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ group: `analyst`,
+ row_level: {
+ filters: [
+ {
+ member: `region`,
+ operator: `equals`,
+ values: [
+ securityContext.groups && securityContext.groups.includes(`emea`)
+ ? `EMEA`
+ : `AMER`
+ ]
+ }
+ ]
+ }
+ }
+ ]
+})
+```
+
+
+
+### Admin override with `allow_all`
+
+To let admins bypass row-level filters that apply to a role, add a second
+policy for the same group that grants [`row_level.allow_all`][ref-ref-dap-row-level]
+when `securityContext.is_admin` is true. Because policies that match the same
+group are combined with _OR_ semantics, the admin policy unlocks every row
+regardless of the more restrictive analyst policy:
+
+
+
+```yaml title="YAML"
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ # Region-restricted access for regular analysts
+ - group: analyst
+ row_level:
+ filters:
+ - member: region
+ operator: equals
+ values: ["{ security_context.region }"]
+
+ # Admin override: full row access when the user is an admin
+ - group: analyst
+ conditions:
+ - if: "{ security_context.is_admin }"
+ row_level:
+ allow_all: true
+```
+
+```javascript title="JavaScript"
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ // Region-restricted access for regular analysts
+ group: `analyst`,
+ row_level: {
+ filters: [
+ {
+ member: `region`,
+ operator: `equals`,
+ values: [securityContext.region]
+ }
+ ]
+ }
+ },
+ {
+ // Admin override: full row access when the user is an admin
+ group: `analyst`,
+ conditions: [
+ { if: securityContext.is_admin }
+ ],
+ row_level: {
+ allow_all: true
+ }
+ }
+ ]
+})
+```
+
+
+
+### Composing boolean logic with `conditions`
+
+`conditions` accept full boolean logic, so you can switch which `row_level`
+applies based on combined checks against the security context and user
+attributes. In YAML, use `and`, `or`, `not`, and parentheses inside
+`{ ... }`. In JavaScript, use `&&`, `||`, and `!`. Multiple `conditions`
+entries on a single policy are combined with _AND_ semantics; multiple
+matching policies are combined with _OR_ semantics.
+
+In the following example, full-time analysts who are _either_ admins _or_
+owners and are _not_ contractors get unrestricted row access; everyone else
+in the `analyst` group falls back to the region-restricted policy above.
+
+
+
+```yaml title="YAML"
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ - group: analyst
+ conditions:
+ - if: "{ user_attributes.is_full_time_employee and user_attributes.tenure_years >= 2 }"
+ - if: "{ user_attributes.is_admin or user_attributes.is_owner }"
+ - if: "{ not (security_context.groups and 'contractors' in security_context.groups) }"
+ row_level:
+ allow_all: true
+```
+
+```javascript title="JavaScript"
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ group: `analyst`,
+ conditions: [
+ { if: userAttributes.is_full_time_employee && userAttributes.tenure_years >= 2 },
+ { if: userAttributes.is_admin || userAttributes.is_owner },
+ { if: !(securityContext.groups && securityContext.groups.includes(`contractors`)) }
+ ],
+ row_level: {
+ allow_all: true
+ }
+ }
+ ]
+})
+```
+
+
+
+## Result
+
+With these policies in place:
+
+- Regional analysts see only rows for the region attached to their security
+context, because only the policy whose `conditions` match contributes its
+`row_level` filter.
+- Admins see all rows, because the admin policy's `row_level.allow_all: true`
+combines with the regional policy via _OR_ semantics.
+- Users without any matching policy are denied access by default.
+
+
+[ref-ref-dap]: /reference/data-modeling/data-access-policies
+[ref-ref-dap-conditions]: /reference/data-modeling/data-access-policies#conditions
+[ref-ref-dap-row-level]: /reference/data-modeling/data-access-policies#row-level
+[ref-dap-rls]: /docs/data-modeling/access-control/data-access-policies#row-level-access
+[ref-sec-ctx]: /docs/data-modeling/access-control/context
diff --git a/docs-mintlify/reference/data-modeling/data-access-policies.mdx b/docs-mintlify/reference/data-modeling/data-access-policies.mdx
index 5698a33e556a5..5ab02668a91e1 100644
--- a/docs-mintlify/reference/data-modeling/data-access-policies.mdx
+++ b/docs-mintlify/reference/data-modeling/data-access-policies.mdx
@@ -208,6 +208,61 @@ cube(`orders`, {
+#### Boolean logic in `if` expressions
+
+`if` expressions support full boolean logic so you can compose checks against
+the [security context][ref-sec-ctx] and user attributes:
+
+- In YAML, expressions inside `{ ... }` use Jinja-style operators: `and`, `or`,
+`not`, and parentheses for grouping.
+- In JavaScript, expressions use native operators: `&&`, `||`, and `!`.
+- Multiple `conditions` entries on a single policy are combined with _AND_
+semantics — every entry must evaluate to `true` for the policy to take effect.
+- Multiple policies that match the same group are combined with _OR_ semantics —
+if any matching policy grants access, the user gets access.
+
+In the following example, a single policy combines three `conditions` entries
+that each use a different boolean operator:
+
+
+
+```yaml title="YAML"
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ - group: manager
+ conditions:
+ - if: "{ user_attributes.is_full_time_employee and user_attributes.tenure_years >= 2 }"
+ - if: "{ user_attributes.is_admin or user_attributes.is_owner }"
+ - if: "{ not (security_context.groups and 'contractors' in security_context.groups) }"
+ member_level:
+ includes: "*"
+```
+
+```javascript title="JavaScript"
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ group: `manager`,
+ conditions: [
+ { if: userAttributes.is_full_time_employee && userAttributes.tenure_years >= 2 },
+ { if: userAttributes.is_admin || userAttributes.is_owner },
+ { if: !(securityContext.groups && securityContext.groups.includes(`contractors`)) }
+ ],
+ member_level: {
+ includes: `*`
+ }
+ }
+ ]
+})
+```
+
+
+
### `member_level`
The optional `member_level` parameter, when present, configures [member-level
@@ -452,6 +507,68 @@ REST (JSON) API][ref-rest-query-filters] queries, allowing to use the same set o
You can also use `and` and `or` parameters to combine multiple filters into
[boolean logical operators][ref-rest-boolean-ops].
+#### `allow_all`
+
+Use the `allow_all` parameter to make the row-level intent of a policy explicit
+without listing any filters:
+
+- `allow_all: true` grants the policy access to all rows. It is equivalent to
+omitting `row_level` (or omitting `filters`) and is useful when you want the
+policy to clearly state that no row-level restriction applies.
+- `allow_all: false` denies the policy access to all rows. Other matching
+policies (if any) still apply on top — see [row-level access][ref-dap-rls].
+
+
+
+```yaml title="YAML"
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ - group: admin
+ row_level:
+ allow_all: true
+
+ - group: guest
+ row_level:
+ allow_all: false
+```
+
+```javascript title="JavaScript"
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ group: `admin`,
+ row_level: {
+ allow_all: true
+ }
+ },
+ {
+ group: `guest`,
+ row_level: {
+ allow_all: false
+ }
+ }
+ ]
+})
+```
+
+
+
+#### Conditional `row_level`
+
+You can make `row_level` conditional so that different filters apply depending
+on the [security context][ref-sec-ctx] or user attributes. In YAML, attach
+[`conditions`](#conditions) to a policy so its `row_level` is skipped when the
+conditions don't match. In JavaScript, you can additionally make `row_level` a
+function of `securityContext` and return different filters at evaluation time.
+When a policy's `row_level` is skipped, other matching policies still apply;
+if no policy matches, access is denied by default. See the [conditional
+row-level access recipe][ref-recipe-conditional-row-level] for worked examples.
+
Note that access policies also respect [row-level security][ref-rls] restrictions
configured via the `query_rewrite` configuration option. See [row-level access][ref-dap-rls] to
learn more about policy evaluation.
@@ -513,4 +630,5 @@ cube(`orders`, {
[ref-mask-dim]: /reference/data-modeling/dimensions#mask
[ref-rest-query-filters]: /reference/rest-api/query-format#filters-format
[ref-rest-query-ops]: /reference/rest-api/query-format#filters-operators
-[ref-rest-boolean-ops]: /reference/rest-api/query-format#boolean-logical-operators
\ No newline at end of file
+[ref-rest-boolean-ops]: /reference/rest-api/query-format#boolean-logical-operators
+[ref-recipe-conditional-row-level]: /recipes/access-control/conditional-row-level-access
\ No newline at end of file