Skip to main content
Version: Latest

Google Workspace: multi-connector setup

This page is not about a single connector — it's about running identos.google-drive, identos.google-gmail, and identos.google-calendar together off a single Google IdP.

One IdP, three connectors

The expected setup looks like this:

identity_provider
└── google (registered once, OAuth client_id/client_secret from Google Cloud)

managed_resource
├── drive-user → google-drive + idp_passthrough + google IdP
├── gmail-user → google-gmail + idp_passthrough + google IdP
├── calendar-user → google-calendar+ idp_passthrough + google IdP
└── calendar-rooms → google-calendar+ google_sa + service account

A single Google login grants access to drive, gmail, and calendar at the same time. A Claude Code session hitting this gateway picks up tools from all three because they're all provisioned against the same authenticated subject.

How scope growth works

The tricky part is OAuth scopes. Each connector declares upstream_scopes on its idp_passthrough auth option — the actual Google OAuth scopes its users need. Drive wants drive.readonly + drive.file; Gmail wants gmail.readonly + gmail.send + gmail.modify + gmail.labels; Calendar wants calendar.readonly + calendar.events.

When you provision a managed resource in idp_passthrough mode, the gateway automatically merges that connector's upstream_scopes into the target IdP's scopes list (IdpScopeMerger). Subsequent user logins at /authorize pass the union of all those scopes to Google, and the user consents once for everything.

before drive-user provision:    idp.scopes = [openid, email]
after drive-user provision: idp.scopes = [openid, email,
drive.readonly, drive.file]
after gmail-user provision: idp.scopes = [... + gmail.readonly,
gmail.send, ...]
after calendar-user provision: idp.scopes = [... + calendar.readonly,
calendar.events]

The merge is additive and idempotent — uninstalling a connector does not remove scopes (another managed resource may still need them, and we can't safely attribute scopes to a single installer).

When a user sees "stored IdP token missing required scopes"

If you install / provision a Google connector after users have already logged in at Google through PBAC, their stored IdP tokens do not carry the newly-added scopes. The first gateway call that needs those scopes fails with a 502:

Stored IdP token missing required scopes: [https://www.googleapis.com/auth/drive.readonly]. User must re-authenticate with step-up.

Two paths out:

  1. Recommended: have the user sign out and back in. On the next /authorize pass, PBAC requests the expanded scope list and the user consents on Google's screen. No operator action required.
  2. Batch: clear upstream_identity_token for the affected users via the admin API; their next interaction will bounce through Google for consent.

Going forward, the rule is: install and provision Google connectors before inviting users to the gateway, and users never see this error.

Pre-configuring the Google OAuth app

On the Google Cloud side, you still need to add these scopes to the OAuth 2.0 client's OAuth consent screen configuration so Google will permit them. The PBAC auto-merge handles the PBAC side; it can't teach Google about scopes its consent screen hasn't been told to offer.

Minimum scopes for all three connectors:

openid
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/drive.readonly
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/gmail.readonly
https://www.googleapis.com/auth/gmail.send
https://www.googleapis.com/auth/gmail.modify
https://www.googleapis.com/auth/gmail.labels
https://www.googleapis.com/auth/calendar.readonly
https://www.googleapis.com/auth/calendar.events

Set the consent screen to External → Production (or Internal for a Workspace-only deployment) once you're past testing and want tokens to survive the 7-day expiry.

Two managed resources, one connector

Running the same connector in both idp_passthrough and google_sa mode requires two managed resources (e.g. calendar-user and calendar-rooms). A single managed resource picks one auth mode at provision time; there's no runtime switch.

The policy layer can tell them apart by input.resource.name if you need different rules for user-mode vs service-account mode (e.g. room_only_mode: true only on calendar-rooms).

Troubleshooting

SymptomLikely causeFix
"Stored IdP token missing required scopes"User logged in before the connector was provisionedRe-log at Google, or clear the upstream_identity_token row
"idp_passthrough requires an authenticated subject"Client used client_credentials (no user context)Either switch the connector to google_sa or issue the call with an authorization_code token
404 on /admin/api/connectors/identos.google-gmail/installJar was built before the connector was addedRebuild the jar (mvn package -DskipTests) and recreate the instance
PDP denies every Gmail send with "recipient domain ... is on the operator denylist"blocked_recipient_domains data is set and a recipient matchesReview the operator-data blob at data.pbac.operator.connectors["identos.google-gmail"]

See also