--- title: "Google BigQuery Row-Level Security" slug: "google-bigquery-row-level-security" updated: 2026-08-23T16:04:23Z published: 2026-08-23T16:04:23Z canonical: "docs.plainid.io/google-bigquery-row-level-security" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.plainid.io/llms.txt > Use this file to discover all available pages before exploring further. # Google BigQuery Row-Level Security **Row-level Security (RLS)** is a fine-grained access control mechanism that restricts which rows of data a principal can access within a BigQuery table. BigQuery implements this using **Row Access Policies (RAPs)**. A Row Access Policy is a table-level object that filters rows at query time based on two components: - A **Grantee List**: the Google Principals (users, Google Groups, etc.) to whom the Policy applies. - A **Filter Expression**: an SQL predicate that determines which rows are visible to the granted principals. Row Access Policies provide dynamic, identity-aware filtering without modifying the underlying data, so users only see rows they're authorized to access. Note BigQuery syntax, supported expressions, and limitations can change independently of the Platform. Always consult the [Google BigQuery documentation](https://cloud.google.com/bigquery/docs) for the current list of valid supported syntaxes and limitations before you deploy a Row-level Policy. Union Logic If a user belongs to multiple groups, each with a different Row Access Policy on the same table, BigQuery applies **union (OR) logic**: the user sees all rows any applicable Policy permits. This aligns with PlainID's standard permissive combining algorithm, so PlainID needs no additional merge logic. For general Native Policy concepts that Row-level and Column-level Policies share (the Native tab, the Protected Resource sub-tab, and how Vendor Compare deploys changes to BigQuery), see [Google BigQuery Native Support](/v1/docs/google-bigquery-native-support). ## Viewing Row-level Policies in PlainID PlainID displays Row-level Policies in **Native** mode. **To view a Row-level Policy in Native:** 1. In the **Policies Workspace**, select the relevant Policy connected to Google BigQuery. 2. On the top navigation bar, click **Native**. 3. The **Native Code** panel displays the Policy Core Logic and Identities Link sections for the Row-level Policy, described in [Policy Core Logic](/docs/google-bigquery-row-level-security#policy-core-logic) and [Identities Link](/docs/google-bigquery-row-level-security#identities-link) below. Learn Mode In Learn Mode, the Native view is read-only. You can view the native Row-level Policy structure, but you can't make changes. ## Asset Type Requirements for Row-level Policies Discovery creates the Asset Type for a BigQuery table automatically, and Manage Mode reuses that same Asset Type when you build a Row-level Policy. You don't need to create or configure an Asset Type yourself. During discovery, the Platform: - Names the Asset Type using the BigQuery resource format: `project_ID.dataset.table_name`. - Maps Asset Attribute names exactly to BigQuery column names, which are **case-sensitive**. - Marks the Asset Type as used for data filtering. - Excludes **JSON columns** from the Asset Type, since BigQuery Row Access Policies don't support filtering on JSON column types. Policy Limit BigQuery allows a maximum of **100 Row Access Policies per table**. PlainID displays a warning if you approach this limit. ## Creating a Row-level Policy from Native Manage Mode Required Switch your Google BigQuery application in the Orchestration Workspace to **Manage Mode** to **create**, **edit**, or **deploy** Row-level Policies from the Policy catalog section. See [Managing POPs](/v1/docs/managing-pops) for more information on how to change the POP Mode. You can create new Row-level Policies for Google BigQuery directly from their native structure. There are three steps when you create a Policy: - Details - Code - What This POP has no Wizard-based creation path. You can only create it through Native. **Details Step**: 1. From the Create Policy drop-down, select **From Native**. 2. On the **Policy Details** step, input a: - Display Name - Change the Policy ID if required - Enter an optional description 1. The Access Type is fixed to **Allow**. BigQuery Row Access Policies only grant visibility into rows, so there's no restrictive option to choose here. 2. In the Google POP Details section, under the Vendor Policy Kind dropdown, choose Row Access Policy. 3. Enter a Vendor Policy Name. 4. Input the following. - **Project ID**: inherited from the POP's Service Account JSON of the selected application (no input required). - **Dataset ID**: select from the datasets discovered by the POP. - **Table ID**: select from the tables discovered for the selected dataset. 5. Input the custom details if applicable to your Policies *(optional)*. 6. Click **Continue**. **Code Step**: In the **Code** step, input the logic and relevant links. Replace the placeholder with the intended filter logic. Each section includes its predefined structure and a logic placeholder, for example: ``` { "filterPredicate": "{{logic placeholder}}" } ``` Tip You can add `//` style inline comments in this step for visibility. They don't show up in the Vendor Compare section and aren't deployed to the Vendor. PlainID retains comments, but a Policy override from the Vendor also overrides the comment. A Row-level Native Policy in BigQuery consists of two sections: **Policy Core Logic** and **Identities Link**. ### Policy Core Logic The Policy Core Logic defines the SQL filter predicate that determines which rows are visible to the granted principals. ``` { "filterPredicate": "" } ``` **Examples:** Simple condition: ``` { "filterPredicate": "region = 'EMEA'" } ``` Compound condition: ``` { "filterPredicate": "col1 = 'one' AND (col2 = 'two' OR col3 = 'three')" } ``` Subquery using `SESSION_USER()`: ``` { "filterPredicate": "col1 IN ( SELECT col2 FROM `plainid-orchestration.name_dataset.nametable6` WHERE col2 = SESSION_USER() )" } ``` JOIN subquery: ``` { "filterPredicate": "col1 IN ( SELECT t10.col4 FROM `plainid-orchestration.name_dataset.nametable9` AS t9 JOIN `plainid-orchestration.name_dataset.nametable10` AS t10 ON t9.col2 = t10.col3 )" } ``` #### Field Reference | Field | Description | Value | | --- | --- | --- | | `filterPredicate` | A SQL Boolean expression that the Row Access Policy applies as the `FILTER USING` clause. The Row Access Policy returns rows where the expression evaluates to `TRUE`. Supports simple comparisons, compound Conditions, and subqueries including `SESSION_USER()`. | string | Important Guidelines - The `filterPredicate` must be a valid GoogleSQL Boolean expression. - Attribute names in the expression must match BigQuery column names exactly and are case-sensitive. - BigQuery Row Access Policies don't support IP address-based filtering. - Row Access Policy filter predicates can't use JSON columns. - Consult the Google BigQuery documentation for the complete, current list of supported syntaxes and limitations, since BigQuery can add or restrict SQL capabilities independently of the Platform. ### Identities Link The Identities Link defines the grantee list: the Google Principals to whom the Row Access Policy applies. ``` { "grantees": ["", ""] } ``` **Example:** ``` { "grantees": ["serviceAccount:bq-emea-reader@plainid-orchestration.iam.gserviceaccount.com"] } ``` **All supported grantee types:** ``` { "grantees": [ "allAuthenticatedUsers", "domain:plainid.com", "group:qa@plainid.com", "serviceAccount:bq-learn-research@acme-orchestration.iam.gserviceaccount.com", "user:name@acme.com" ] } ``` #### Field Reference | Field | Description | Value | | --- | --- | --- | | `grantees` | An array of Google Principal identifiers to whom the Row Access Policy grants access. | array of strings | **Supported principal types:** | Principal | Description | | --- | --- | | `allAuthenticatedUsers` | All users authenticated with a Google Account | | `domain:<domain>` | All users in a Google Workspace domain (e.g., `domain:plainid.com`) | | `group:<email>` | A Google Group (e.g., `group:analysts@example.com`) | | `serviceAccount:<email>` | A GCP Service Account (e.g., `serviceAccount:name@project.iam.gserviceaccount.com`) | | `user:<email>` | A specific Google Account (e.g., `user:alice@example.com`) | **What Step** In the **What** Step, add the relevant table as an Asset Type. Ensure it's the same table you set as the Table ID in the Details step. ## Deploying Policy Changes When you discover or edit a Row-level Policy in Manage Mode, PlainID doesn't push the changes to BigQuery automatically. Use the **Policy Deploy** operation to: - Accept the vendor's version of a single Policy, discarding the pending Platform change. - Accept the Platform's version of a single Policy, or all pending Policies, and push the update to BigQuery. The Platform marks discrepancies between the vendor and Platform versions of a Policy, and you can review them side by side in **Vendor Compare**. For general information on how the Native tab, Protected Resource linking, and Vendor Compare work, see [Google BigQuery Native Support](/v1/docs/google-bigquery-native-support). Validation Happens at Deploy The Platform doesn't validate the native filter syntax when you save changes. Validation happens in BigQuery when you deploy the Policy. If BigQuery rejects the Policy, PlainID returns the error and displays it on the Policy in Side-by-Side and Vendor Compare. ## Known Limitations | Limitation | Details | | --- | --- | | **Native Mode** | You can only use this POP in Native Mode. | | **IP Address Filtering** | BigQuery Row Access Policies don't support IP address-based filtering in the `filterPredicate`. | | **Linked Asset** | You can't unlink or replace the table linked to a Row-level Policy. | | **Vendor Policy Section** | The Vendor Policy section shown in Vendor Compare is metadata only. You can't edit it, including through Policy-as-Code import. |