← All posts
Data Engineering13 min read

dbt Authorized Views in BigQuery: Fix Broken Access Control

Most dbt BigQuery teams grant dataset-level IAM instead of using authorized views — here's why that breaks security and exactly how to fix it.

dbt Authorized Views in BigQuery: The Access Control Pattern Most Teams Get Wrong

dbt authorized views in BigQuery let a view expose data from a protected dataset without granting the querying user direct access to the underlying tables. When misconfigured — or simply not used at all — teams end up either locking analysts out of data they need, or over-granting IAM permissions that expose far more than intended. This is one of the most quietly consequential mistakes we see in production dbt BigQuery projects.

If you have ever received a Access Denied: BigQuery BigQuery: Permission denied while getting Drive credentials error when a view queries another dataset, or found yourself handing out roles/bigquery.dataViewer on an entire raw dataset just to make a dashboard work, this post is for you. The problem is structural, and the fix is built directly into dbt.


Why Does the "Just Grant IAM" Instinct Break Everything?

When a dbt model in one dataset queries a table in a different dataset, BigQuery checks permissions at runtime against the querying user's identity — not the service account that created the view. This surprises most people the first time they encounter it.

Here is the scenario that plays out repeatedly in fast-growing companies:

  1. A data engineer builds a reporting model in dataset_reporting that joins against raw tables in dataset_raw.
  2. An analyst tries to query the reporting model in a BI tool. Access denied.
  3. The engineer, under time pressure, grants roles/bigquery.dataViewer on dataset_raw to the analyst's user group.
  4. The analyst can now query the reporting model — but they can also query every raw table directly, including tables containing PII, raw card data, or unmasked financial records.

That is not a controlled access model. That is accidental data exposure dressed up as a workaround.

The core issue is that a standard BigQuery view does not carry its own permissions to read the underlying tables. Implementing a view and restricting access by just using service accounts does not work, because you also need to give the service account permission to access the base table — and this scenario is precisely what authorized views are designed to handle.

The pattern we see repeatedly in early-stage companies — particularly those that have scaled their dbt project quickly without stopping to design an access layer — is a dataset_raw or dataset_staging with viewer permissions granted to half the organisation, because no one had time to set up authorized views properly. When we audit these projects, the blast radius of a compromised analyst credential is often far wider than anyone realised.


dbt authorized view access control architecture in BigQuery showing broken vs fixed permission chain


📺 Watch: Steps to set up Authorized View in BigQuery with Principle of least Privilege | PDE & PCA Concepts

Steps to set up Authorized View in BigQuery with Principle of least Privilege | PDE & PCA Concepts


What Are dbt Authorized Views in BigQuery, and How Do They Work?

An authorized view is a BigQuery view that has been explicitly registered as a trusted entity on a source dataset. Once authorized, the view can query the underlying tables in that dataset on behalf of any user who has access to the view — without those users needing direct access to the source tables.

An authorized view lets you share query results with particular users and groups without giving them access to the underlying source data. An authorized dataset lets you authorize all of the views in a specified dataset to access the data in the shared dataset.

In dbt, this is configured using the grant_access_to parameter in your model config. When configured, dbt provides an authorized view access to show partial information from other datasets, without providing end users with full access to those underlying datasets.

Here is what the configuration looks like in a schema.yml or model-level config block:

models:
  - name: fct_transactions
    config:
      materialized: view
      grant_access_to:
        - project: my_gcp_project
          dataset: dataset_raw
        - project: my_gcp_project
          dataset: dataset_staging

When dbt runs this model, it registers fct_transactions as an authorized view on both dataset_raw and dataset_staging. Any analyst querying fct_transactions through a BI tool or the BigQuery console gets the data — but they cannot traverse down into the raw or staging layers directly.

This is the correct pattern. The view holds the cross-dataset permission, not the user.

An authorized view allows data sharing without giving users access to the underlying objects, and it is also a great way to share data across BigQuery projects — making the users from the target project responsible for the query costs.

That last point matters. In multi-project architectures, authorized views let you expose data from a centralised data platform project into consumer projects without duplicating data or handing out IAM roles on your core infrastructure.


What Actually Goes Wrong in Production — And How to Diagnose It

If you are not using grant_access_to and your dbt models span multiple datasets, you will run into one of two failure modes:

Failure Mode 1: Access denied errors that appear only in production

During development, the engineer running dbt run has broad project-level permissions. Everything looks fine. But when an analyst hits the same view through Looker, Holistics, or the BigQuery console, they get an access denied error — because the underlying tables are in a dataset the analyst has never been granted access to.

Teams often waste hours debugging this before realising the view itself needs to be authorized. The error message from BigQuery does not clearly distinguish between "you cannot access the view" and "the view cannot access its source tables on your behalf."

Failure Mode 2: Accidental over-permission to fix Failure Mode 1

As described above, the workaround-under-pressure is to grant IAM on the source dataset. This works, but it creates a security liability. In fintech and financial services specifically, this is a compliance problem — raw payment, KYC, or lending data should never be directly queryable by a broad user group, even if the intent was just to make the reporting layer work.

We encountered exactly this situation with a Series A payments company. Their dataset_raw had roles/bigquery.dataViewer granted to an allAnalysts Google Group with over forty members — because it was the fastest way to fix a broken Looker connection six months earlier. Nobody had documented it. When we audited the project, that group could directly query raw transaction records, unmasked cardholder names, and PSP settlement data. The fix took about two hours; the risk had been sitting there for months.

How to check whether you have the problem right now

Run the following query in INFORMATION_SCHEMA to identify views in your reporting or mart datasets that reference tables in other datasets but are not registered as authorized views:

SELECT
  table_schema AS view_dataset,
  table_name AS view_name,
  view_definition
FROM
  `your_project`.INFORMATION_SCHEMA.VIEWS
WHERE
  view_definition LIKE '%dataset_raw%'
  OR view_definition LIKE '%dataset_staging%'
ORDER BY
  table_schema, table_name;

For each view returned, check whether it appears in the authorized views list of the referenced dataset. In the BigQuery console, navigate to the source dataset → Sharing → Authorised views. If your cross-dataset views are not listed there, your access model is broken — either analysts are locked out, or you have compensated with over-broad IAM.

If you want to go deeper on cost attribution while you're in INFORMATION_SCHEMA, see our post on BigQuery INFORMATION_SCHEMA Cost Attribution: Stop the Guessing — the same pattern of diagnostic querying applies.

If you are looking to build a clean access control architecture on top of an existing dbt project, explore how Fintel Analytics approaches data engineering engagements — we regularly help growth-stage companies audit and rebuild their access layer without disrupting production.


Data engineer reviewing BigQuery multi-layer dataset security architecture with dbt authorized views

How to Implement dbt Authorized Views Correctly: The Right Architecture

The correct pattern separates your BigQuery project into distinct layers, each with a defined access boundary:

Layer 1 — Raw / Staging datasets (dataset_raw, dataset_staging) No analyst IAM. Only the dbt service account has write access. No human should be able to directly query these tables outside of debugging.

Layer 2 — Intermediate / Mart datasets (dataset_marts) dbt models here are materialised as views or tables. Any view that reads from Layer 1 must be registered as an authorized view on those Layer 1 datasets using grant_access_to.

Layer 3 — Reporting / BI layer Analysts and BI tools (Looker, Holistics, etc.) are granted roles/bigquery.dataViewer on dataset_marts only. They query mart models and never touch raw or staging.

The grant_access_to config lives in your dbt model YAML. You can apply it at the model level for surgical control, or at the folder level using dbt_project.yml:

models:
  your_project:
    marts:
      +grant_access_to:
        - project: your_gcp_project
          dataset: dataset_raw
        - project: your_gcp_project
          dataset: dataset_staging

This registers every model in the marts/ folder as an authorized view on both source datasets whenever dbt run executes. You do not need to manually manage this in the BigQuery console — dbt handles the registration on each run.

The authorized dataset limitation to know about

Per BigQuery documentation, a dataset's access control list can have up to 2,500 total authorized resources. For most companies at Series A or earlier, this limit is irrelevant. But if you are building a large multi-tenant dbt project with hundreds of models referencing the same source dataset, be aware the limit exists. It is possible to create a large number of authorized views for each object in a downstream dataset, but this can get messy quickly — which is why authorized datasets (rather than individual authorized views) are the more scalable pattern.

What about grants vs grant_access_to?

These are two distinct dbt BigQuery features that are often confused:

  • grant_access_to — registers your dbt view as an authorized view on a source dataset. Controls what the view can read.
  • grants — assigns IAM roles to users, groups, or service accounts on the output model. Controls who can query the view.

You can use the two features together: authorize a view model with the grant_access_to configuration, and then add grants to that view model to share its query results — and only its query results — with other users, groups, or service accounts.

Used together, these two configs give you a complete, code-managed access control layer in dbt — no manual IAM configuration in the console, no undocumented grants that survive engineer turnover.


The Compounding Problem: dbt Multi-Project Architectures and Cross-Project Authorized Views

If you are running a dbt multi-project architecture in BigQuery — for example, a core data platform project consumed by domain-specific dbt projects — the authorized view pattern becomes even more important and more frequently mishandled.

In a multi-project setup, your mart models in project_platform need to be authorised on the raw datasets in the same project. But your downstream dbt models in project_finance or project_product may query views that live in project_platform. This creates a cross-project authorization chain.

The grant_access_to config supports cross-project references — you specify both the project and dataset. But here is what we see teams get wrong:

  • They authorise the view in the consumer project's datasets, when the authorization needs to happen on the source dataset in the platform project.
  • They forget that when a consumer project's user queries a cross-project view, BigQuery evaluates the authorized view registration on the source dataset in the platform project — not on anything in the consumer project.
  • They assume that if the dbt service account can query both projects, the end-user will be able to as well. It will not — the user's own identity is evaluated at runtime for non-authorized views.

The diagnostic is the same: check the authorized views list on each source dataset. If your cross-project view is not registered there, the chain is broken.

A pattern we see repeatedly in fintech companies that have grown quickly: the platform team builds a clean mart layer, authorises views correctly in development, but when a new domain dataset is added six months later without following the same process, analysts start getting access denied errors from a production dashboard — and the root cause takes half a day to find because nobody knows where to look.

Documenting the access architecture in your dbt project's README and enforcing grant_access_to as a requirement for any cross-dataset mart model is the fix. Make it a dbt PR checklist item.


Frequently Asked Questions

Q: What is a dbt authorized view in BigQuery and when do I need one?

A: A dbt authorized view is a BigQuery view that has been registered as a trusted entity on a source dataset, allowing it to read from that dataset without the querying user needing direct IAM access to the underlying tables. You need one any time a dbt view model reads from a dataset that your analysts or BI tools should not have direct access to — which is effectively any cross-dataset view in a properly segmented data warehouse.

Q: How do I configure grant_access_to in dbt for BigQuery?

A: Add the grant_access_to config to your model's YAML definition or to a folder-level config in dbt_project.yml. Specify the project and dataset of every source dataset your view reads from. When dbt run executes the model, dbt automatically registers it as an authorized view on each listed dataset. You do not need to manually configure this in the BigQuery console.

Q: What is the difference between grant_access_to and grants in dbt BigQuery?

A: grant_access_to controls what a view can read — it registers the view as authorized on source datasets. grants controls who can query the view — it assigns IAM roles to users or groups on the output model. You typically need both: grant_access_to to give the view read permission on raw data, and grants to give analysts query access to the mart model.

Q: Why do dbt authorized views work in development but break in production for analysts?

A: During development, the dbt engineer typically has broad project-level IAM permissions, so BigQuery can resolve cross-dataset reads without authorized view registration. In production, when an analyst with narrower permissions queries the view, BigQuery evaluates their identity against the source dataset's ACL — and if the view is not registered as authorized, access is denied. The fix is grant_access_to, not broader analyst IAM.

Q: Is there a limit to the number of authorized views in BigQuery?

A: Yes. BigQuery's access control list supports up to 2,500 total authorized resources per dataset. For most growth-stage companies this limit is not a concern, but large multi-tenant platforms with many mart models referencing a single source dataset should use authorized datasets rather than individual authorized views to stay within the limit and simplify maintenance.


If your dbt BigQuery project spans multiple datasets or projects and you have never audited your authorized views configuration, there is a meaningful chance that analysts have either broader IAM than intended or are working around access errors in ways that compound over time. At Fintel Analytics, we have helped fintech, payments, and SaaS businesses rebuild their access architecture from the ground up — replacing ad-hoc IAM grants with a clean, code-managed layer in dbt that survives team changes, dataset additions, and regulatory scrutiny. If your access control model was built under time pressure and has never been properly reviewed, that is exactly the kind of problem we fix.

← Back to all posts