Stitchflow
BigQuery logo

BigQuery User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 4, 2026

Summary and recommendation

BigQuery has no standalone user management API and no native SCIM endpoint. Access control is split across two separate API surfaces: the Cloud Resource Manager API (for project-level IAM bindings, including roles like roles/bigquery.admin and roles/bigquery.jobUser) and the BigQuery API itself (for dataset-level IAM policies via getIamPolicy/setIamPolicy, and legacy dataset ACLs via the datasets resource).

User account lifecycle - creating, suspending, or deleting Google accounts - is handled by a third surface: the Cloud Identity API or Google Workspace Admin SDK.

For teams building automated provisioning, the recommended pattern is group-based: provision users into Cloud Identity groups via the Cloud Identity API, then bind those groups to BigQuery IAM roles once. Individual user grants require touching every dataset and project binding separately, which does not scale.

The Stitchflow MCP server with ~100 deep IT/identity integrations handles the cross-surface orchestration - Cloud Identity group membership, project-level IAM, and dataset-level policy - as a unified provisioning flow rather than three independent API sequences.

Auth requires OAuth 2.0 with a service account granted roles/bigquery.admin and roles/resourcemanager.projectIamAdmin at minimum. The https://www.googleapis.com/auth/cloud-platform scope covers both the BigQuery and Cloud Resource Manager APIs; narrower scopes (https://www.googleapis.com/auth/bigquery) are sufficient for dataset-level operations only.

API quick reference

Has user APIYes
Auth methodOAuth 2.0 (service account or user credentials via Google Auth Library; Bearer token in Authorization header)
Base URLOfficial docs
SCIM availableNo
SCIM plan requiredN/A

Authentication

Auth method: OAuth 2.0 (service account or user credentials via Google Auth Library; Bearer token in Authorization header)

Setup steps

  1. Create a Google Cloud project and enable the BigQuery API and Cloud IAM API in the Google Cloud Console.
  2. Create a service account (IAM & Admin > Service Accounts) and grant it appropriate roles (e.g., roles/bigquery.admin, roles/resourcemanager.projectIamAdmin).
  3. Download the service account JSON key or use Workload Identity Federation for keyless auth.
  4. Obtain an OAuth 2.0 access token: use 'gcloud auth application-default login' for user credentials or the Google Auth Library for service accounts.
  5. Pass the token as 'Authorization: Bearer ' in all API requests.
  6. For user provisioning, also enable the Cloud Identity API and grant the service account roles/cloudidentity.groups.admin or equivalent.

Required scopes

Scope Description Required for
https://www.googleapis.com/auth/bigquery Full access to BigQuery resources including dataset IAM policies. Reading and writing BigQuery dataset IAM policies (getIamPolicy, setIamPolicy)
https://www.googleapis.com/auth/cloud-platform Full access to all Google Cloud services including IAM. Managing project-level IAM bindings via Cloud Resource Manager API
https://www.googleapis.com/auth/iam Manage IAM policies and service accounts. Service account and IAM policy management
https://www.googleapis.com/auth/cloud-identity.groups Manage Cloud Identity groups and memberships. Creating/managing groups used for BigQuery access control

User object / data model

Field Type Description On create On update Notes
members[] string[] IAM member identifiers in the policy binding (e.g., 'user:alice@example.com', 'group:team@example.com', 'serviceAccount:sa@project.iam.gserviceaccount.com'). required required Format: 'user:', 'group:', 'serviceAccount:', 'domain:', or 'allUsers'/'allAuthenticatedUsers'.
role string IAM role to assign (e.g., 'roles/bigquery.dataViewer', 'roles/bigquery.dataEditor', 'roles/bigquery.admin'). required required Predefined BigQuery roles: roles/bigquery.user, roles/bigquery.dataViewer, roles/bigquery.dataEditor, roles/bigquery.dataOwner, roles/bigquery.jobUser, roles/bigquery.admin.
condition object Optional IAM condition expression for attribute-based access control. optional optional Requires IAM Conditions; includes 'title', 'description', 'expression' (CEL syntax).
etag string Optimistic concurrency control token for the IAM policy. Must be included in setIamPolicy to prevent concurrent modification conflicts. not applicable required Retrieve via getIamPolicy, then pass back in setIamPolicy.
version integer IAM policy version. Use version 3 to support conditions. optional optional Default is 1. Set to 3 when using IAM conditions.
access[].role string BigQuery dataset-level legacy access role: READER, WRITER, OWNER. optional optional Dataset.access[] is a legacy mechanism; prefer IAM policies.
access[].userByEmail string Email address of a user granted dataset access via legacy dataset ACL. optional optional Part of Dataset resource access[] array.
access[].groupByEmail string Email address of a Google Group granted dataset access via legacy dataset ACL. optional optional Part of Dataset resource access[] array.
access[].specialGroup string Special group identifier: 'projectOwners', 'projectReaders', 'projectWriters', 'allAuthenticatedUsers'. optional optional Part of Dataset resource access[] array.
access[].iamMember string IAM member string for dataset-level access (e.g., 'user:alice@example.com'). optional optional Bridges legacy dataset ACL with IAM-style member strings.

Core endpoints

Get IAM policy for a dataset

  • Method: POST
  • URL: https://bigquery.googleapis.com/bigquery/v2/projects/{projectId}/datasets/{datasetId}:getIamPolicy
  • Watch out for: Returns only IAM policies set at the dataset level. Project-level IAM bindings are inherited but not returned here; query Cloud Resource Manager for those.

Request example

POST /bigquery/v2/projects/my-project/datasets/my_dataset:getIamPolicy
Authorization: Bearer <token>
Content-Type: application/json
{}

Response example

{
  "version": 1,
  "etag": "BwXyz==",
  "bindings": [
    {"role":"roles/bigquery.dataViewer","members":["user:alice@example.com"]}
  ]
}

Set IAM policy for a dataset (grant/revoke user access)

  • Method: POST
  • URL: https://bigquery.googleapis.com/bigquery/v2/projects/{projectId}/datasets/{datasetId}:setIamPolicy
  • Watch out for: This is a full replace operation. Always fetch the current policy via getIamPolicy first, modify the bindings, then call setIamPolicy with the retrieved etag to avoid overwriting concurrent changes.

Request example

POST /bigquery/v2/projects/my-project/datasets/my_dataset:setIamPolicy
Authorization: Bearer <token>
Content-Type: application/json
{
  "policy": {
    "version": 1,
    "etag": "BwXyz==",
    "bindings": [{"role":"roles/bigquery.dataViewer","members":["user:alice@example.com"]}]
  }
}

Response example

{
  "version": 1,
  "etag": "BwABC==",
  "bindings": [
    {"role":"roles/bigquery.dataViewer","members":["user:alice@example.com"]}
  ]
}

Get project-level IAM policy (for BigQuery project roles)

  • Method: POST
  • URL: https://cloudresourcemanager.googleapis.com/v3/projects/{projectId}:getIamPolicy
  • Watch out for: Requires roles/resourcemanager.projectIamAdmin or roles/owner on the project. BigQuery project-level roles (e.g., roles/bigquery.admin) are managed here, not via the BigQuery API.

Request example

POST /v3/projects/my-project:getIamPolicy
Authorization: Bearer <token>
Content-Type: application/json
{}

Response example

{
  "version": 1,
  "etag": "BwXyz==",
  "bindings": [
    {"role":"roles/bigquery.admin","members":["user:admin@example.com"]}
  ]
}

Set project-level IAM policy (grant/revoke BigQuery project roles)

  • Method: POST
  • URL: https://cloudresourcemanager.googleapis.com/v3/projects/{projectId}:setIamPolicy
  • Watch out for: Full replace semantics. Omitting an existing binding removes it. Use read-modify-write pattern with etag.

Request example

POST /v3/projects/my-project:setIamPolicy
Authorization: Bearer <token>
Content-Type: application/json
{
  "policy": {
    "version": 1,
    "etag": "BwXyz==",
    "bindings": [{"role":"roles/bigquery.jobUser","members":["user:bob@example.com"]}]
  }
}

Response example

{
  "version": 1,
  "etag": "BwDEF==",
  "bindings": [
    {"role":"roles/bigquery.jobUser","members":["user:bob@example.com"]}
  ]
}

Get dataset (includes legacy access[] ACL)

  • Method: GET
  • URL: https://bigquery.googleapis.com/bigquery/v2/projects/{projectId}/datasets/{datasetId}
  • Watch out for: The access[] array is a legacy ACL mechanism. It coexists with IAM policies but is separate. Prefer IAM policies for new integrations.

Request example

GET /bigquery/v2/projects/my-project/datasets/my_dataset
Authorization: Bearer <token>

Response example

{
  "datasetReference": {"projectId":"my-project","datasetId":"my_dataset"},
  "access": [
    {"role":"READER","userByEmail":"alice@example.com"},
    {"role":"OWNER","specialGroup":"projectOwners"}
  ]
}

Update dataset access (legacy ACL via patch)

  • Method: PATCH
  • URL: https://bigquery.googleapis.com/bigquery/v2/projects/{projectId}/datasets/{datasetId}
  • Watch out for: Patching access[] replaces the entire access array. Fetch the current dataset first and merge changes before patching.

Request example

PATCH /bigquery/v2/projects/my-project/datasets/my_dataset
Authorization: Bearer <token>
Content-Type: application/json
{
  "access": [
    {"role":"READER","userByEmail":"alice@example.com"},
    {"role":"WRITER","userByEmail":"bob@example.com"}
  ]
}

Response example

{
  "datasetReference": {"projectId":"my-project","datasetId":"my_dataset"},
  "access": [
    {"role":"READER","userByEmail":"alice@example.com"},
    {"role":"WRITER","userByEmail":"bob@example.com"}
  ]
}

List Cloud Identity group members (for group-based BigQuery access)

  • Method: GET
  • URL: https://cloudidentity.googleapis.com/v1/groups/{groupName}/memberships
  • Watch out for: Group ID must be the Cloud Identity internal group name (not email). Use groups.lookup to resolve group email to group name first.

Request example

GET /v1/groups/groups%2F01234abcde/memberships
Authorization: Bearer <token>

Response example

{
  "memberships": [
    {"name":"groups/01234abcde/memberships/56789",
     "preferredMemberKey":{"id":"alice@example.com"},
     "roles":[{"name":"MEMBER"}]}
  ],
  "nextPageToken": "..."
}

Add member to Cloud Identity group

  • Method: POST
  • URL: https://cloudidentity.googleapis.com/v1/groups/{groupName}/memberships
  • Watch out for: Returns a long-running operation, not the membership directly. Poll the operation to confirm completion. User must have a Google account in the same or a trusted domain.

Request example

POST /v1/groups/groups%2F01234abcde/memberships
Authorization: Bearer <token>
Content-Type: application/json
{
  "preferredMemberKey": {"id": "bob@example.com"},
  "roles": [{"name": "MEMBER"}]
}

Response example

{
  "name": "operations/memberships.create/...",
  "done": false
}

Rate limits, pagination, and events

  • Rate limits: BigQuery API and Cloud IAM API have separate quota systems. BigQuery API requests are subject to per-project quotas. IAM API has its own limits.
  • Rate-limit headers: No
  • Retry-After header: No
  • Rate-limit notes: Quota errors return HTTP 429 or 403 with reason 'rateLimitExceeded' or 'userRateLimitExceeded'. Use exponential backoff. IAM setIamPolicy has a limit of 1 request/second per resource to avoid contention. Quotas can be increased via Google Cloud Console quota requests.
  • Pagination method: token
  • Default page size: 0
  • Max page size: 0
  • Pagination pointer: pageToken
Plan Limit Concurrent
Google Cloud (all tiers) BigQuery API: 300 requests/second/user; IAM API: 600 requests/minute for setIamPolicy per project 0
  • Webhooks available: No
  • Webhook notes: BigQuery and Google Cloud IAM do not offer native webhooks for user/access change events. Changes can be monitored via Cloud Audit Logs.
  • Alternative event strategy: Use Cloud Audit Logs (Admin Activity and Data Access logs) exported to Pub/Sub via a Log Sink to receive near-real-time notifications of IAM policy changes and BigQuery access events. Configure via Cloud Logging: https://cloud.google.com/logging/docs/export/configure_export_v2

SCIM API status

  • SCIM available: No
  • SCIM version: Not documented
  • Plan required: N/A
  • Endpoint: Not documented

Limitations:

  • BigQuery has no native SCIM endpoint.
  • User provisioning for BigQuery access is handled by provisioning users into Google Workspace or Cloud Identity, then assigning IAM roles via the Cloud IAM or BigQuery APIs.
  • Google Workspace supports SCIM provisioning from IdPs (Okta, Azure AD, etc.) to manage the underlying Google accounts, but this is a Google Workspace feature, not a BigQuery feature.
  • After users exist in Cloud Identity/Google Workspace, BigQuery access must be granted separately via IAM policy APIs.

Common scenarios

Three provisioning scenarios cover the majority of integration use cases, each with distinct API surface requirements.

Granting dataset read access: POST to /projects/{projectId}/datasets/{datasetId}:getIamPolicy to retrieve the current policy and etag, add a roles/bigquery.dataViewer binding, then POST to :setIamPolicy with the modified policy. Separately, POST to the Cloud Resource Manager /projects/{projectId}:setIamPolicy to add roles/bigquery.jobUser - without this, the user can see the dataset but cannot execute queries against it.

Group-based provisioning (recommended for scale): resolve the Cloud Identity group name via GET /v1/groups:lookup?groupKey.id={groupEmail}, then POST to /v1/groups/{groupName}/memberships with the new member. This returns a long-running operation - poll until done=true before treating the change as effective. IAM propagation after setIamPolicy calls can take up to 60 seconds.

Offboarding: remove the user from all relevant Cloud Identity group memberships, then independently call getIamPolicy/setIamPolicy on each dataset to remove direct member bindings, and repeat for the project-level policy via Cloud Resource Manager. Group removal and direct IAM binding removal are independent operations - both must be completed. Also audit legacy dataset access[] ACL entries, which are a separate system from IAM policies and are not cleaned up by IAM operations.

Grant a user read access to a specific BigQuery dataset

  1. Obtain an OAuth 2.0 access token with scope https://www.googleapis.com/auth/bigquery.
  2. Call POST https://bigquery.googleapis.com/bigquery/v2/projects/{projectId}/datasets/{datasetId}:getIamPolicy to retrieve the current policy and etag.
  3. Add a new binding: {"role": "roles/bigquery.dataViewer", "members": ["user:alice@example.com"]} to the policy bindings array.
  4. Call POST https://bigquery.googleapis.com/bigquery/v2/projects/{projectId}/datasets/{datasetId}:setIamPolicy with the modified policy including the original etag.
  5. If the user also needs to run jobs, separately call Cloud Resource Manager setIamPolicy to add roles/bigquery.jobUser at the project level.

Watch out for: Forgetting to grant roles/bigquery.jobUser at the project level means the user can see the dataset but cannot run queries against it.

Provision a new user with BigQuery access via group membership

  1. Ensure the user account exists in Google Workspace or Cloud Identity (provision via Google Workspace Admin SDK or SCIM to Google Workspace if using an IdP).
  2. Resolve the Cloud Identity group name: GET https://cloudidentity.googleapis.com/v1/groups:lookup?groupKey.id=bq-analysts@example.com.
  3. Add the user to the group: POST https://cloudidentity.googleapis.com/v1/groups/{groupName}/memberships with body {"preferredMemberKey":{"id":"newuser@example.com"},"roles":[{"name":"MEMBER"}]}.
  4. Poll the returned long-running operation until done=true.
  5. Ensure the group already has the appropriate IAM bindings on the relevant BigQuery datasets and project (set once, applies to all group members).

Watch out for: Group-based access is the recommended scalable approach. IAM changes for the group propagate to all members but may take up to 60 seconds.

Revoke a user's BigQuery access upon offboarding

  1. Remove the user from all Cloud Identity groups that have BigQuery IAM bindings (DELETE membership via Cloud Identity API).
  2. Call getIamPolicy on each relevant BigQuery dataset and remove the user's direct member entries from all bindings.
  3. Call setIamPolicy on each dataset with the updated policy (including etag).
  4. Call Cloud Resource Manager getIamPolicy for the project, remove the user from all BigQuery-related role bindings, and call setIamPolicy.
  5. Optionally, disable or delete the user's Google Workspace/Cloud Identity account via the Admin SDK to prevent all Google Cloud access.

Watch out for: Direct IAM bindings and group memberships are independent. Removing a user from groups does not remove direct IAM bindings, and vice versa. Both must be cleaned up. Also check for service account keys or impersonation permissions the user may have been granted.

Why building this yourself is a trap

The primary integration trap is setIamPolicy's full-replace semantics. Both the BigQuery dataset setIamPolicy and the Cloud Resource Manager project setIamPolicy replace the entire policy on each call. Any binding omitted from the request body is silently deleted.

Implementations that construct a new policy from scratch rather than following a strict read-modify-write pattern with the retrieved etag will cause accidental permission removal under concurrent writes - a failure mode that is difficult to detect and can affect all users on the project or dataset.

A second trap is the coexistence of two independent access systems on BigQuery datasets: IAM policies (managed via getIamPolicy/setIamPolicy) and legacy access[] ACLs (managed via GET/PATCH on the dataset resource). These systems are additive but separate. An integration that manages only IAM policies will leave legacy ACL entries intact, and vice versa.

Auditing effective permissions requires querying both systems and merging the results.

Finally, Cloud Identity group membership changes return long-running operations, not synchronous confirmations. Integrations that do not poll for operation completion may proceed assuming a membership change is effective when it is still pending - leading to access gaps or false-positive provisioning confirmations.

IAM policy propagation adds a further delay of up to 60 seconds after a successful setIamPolicy call.

Automate BigQuery workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 4, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

Abnormal Security logo

Abnormal Security

API Only
AutomationAPI only
Last updatedMar 2026

Abnormal Security is an enterprise email security platform focused on detecting and investigating threats such as phishing, account takeover (ATO), and vendor email compromise. It does not support SCIM provisioning, which means every app in your stack

ActiveCampaign logo

ActiveCampaign

API Only
AutomationAPI only
Last updatedFeb 2026

ActiveCampaign uses a group-based permission model: every user belongs to exactly one group, and all feature-area access (Contacts, Campaigns, Automations, Deals, Reports, Templates) is configured at the group level, not per individual. The default Adm

ADP logo

ADP

API Only
AutomationAPI only
Last updatedFeb 2026

ADP Workforce Now is a mid-market to enterprise HCM platform that serves as the HR source of record for employee data — payroll, benefits, time, and talent. User access is governed by a hybrid permission model: predefined security roles (Security Maste