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:
- Recommended: have the user sign out and back in. On the next
/authorizepass, PBAC requests the expanded scope list and the user consents on Google's screen. No operator action required. - Batch: clear
upstream_identity_tokenfor 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
| Symptom | Likely cause | Fix |
|---|---|---|
| "Stored IdP token missing required scopes" | User logged in before the connector was provisioned | Re-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/install | Jar was built before the connector was added | Rebuild 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 matches | Review the operator-data blob at data.pbac.operator.connectors["identos.google-gmail"] |
See also
- Google Drive connector
- Gmail connector
- Google Calendar connector
- MCP clients — how Claude Code and other MCP clients attach to the gateway