Skip to content

feat(credentials): keyless Google Workspace domain-wide delegation via IAM signJwt - #9933

Merged
waleedlatif1 merged 12 commits into
stagingfrom
feat/google-workspace-keyless-dwd
Nov 12, 2026
Merged

waleedlatif1 merged 12 commits into
stagingfrom
feat/google-workspace-keyless-dwd

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • A keyless (Workload Identity Federation) Google service account credential can now use domain-wide delegation for Gmail, Google Drive, Google Docs, Google Sheets and Google Calendar, with no JSON key. The flow is: Sim token → STS → IAM Credentials signJwt (sub = the Workspace user) → jwt-bearer exchange at oauth2.googleapis.com/token.
  • Delegation is an optional, additive delegation: { user, services } in the keyless config. The credential acts only as its stored user. A run that sets a different Impersonated Account is refused before Google is contacted (the comparison ignores case and surrounding spaces).
  • Authorization is by scope, as Google's is. Any scope outside the delegated services' scopes is refused before Google is contacted, so Drive, Docs and Sheets, which share scopes, serve each other. A read-only scope is minted as the authorized scope that covers it: its read-write sibling (drive.readonly → drive, for the Drive picker), or gmail.modify for gmail.readonly (the Gmail label picker and the knowledge base connector).
  • Saving proves the whole chain: one delegated mint per scope set and one cheap read per service as the user. The stray-subject pin probe also checks that signJwt is refused. Token-endpoint refusals get copy for each of Google's documented error codes: Admin-console authorization for unauthorized_client and access_denied, admin policy, a disabled or deleted service account, and neutral copy for anything else.
  • The dialog offers keyless mode for these five services with a service picker and a Workspace user field. It works from every entry point: the block credential selector, the Integrations page and the chat connect card. The first passes a service id (gmail); the other two pass the OAuth provider id (google-email), and both are accepted. It lists the scopes to authorize in the Admin console, and its gcloud commands switch to roles/iam.serviceAccountTokenCreator, because roles/iam.workloadIdentityUser lacks iam.serviceAccounts.signJwt. A reconnect keeps the stored delegation, read through the per-provider reconnect map with no provider branch in the shared use case.
  • Tokens are cached by credential, secret version, delegated user and scopes. The assertion exchange reuses the JSON-key transport (redirect error, bounded read, retry budget).

Product update (if relevant)

Workspace admins can connect Gmail, Drive, Docs, Sheets and Calendar to one Workspace user without creating a service account key, which Google's DWD best practices recommend. Docs: Google service account → keyless domain-wide delegation.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

  • Unit tests against a fake Google (STS, IAM, token endpoint, Workspace reads). They cover:
    • the save chain and the per-service reads
    • refused roles and grants, and the pin probe
    • refused subject mismatch and scopes, plus scope-level authorization across Drive, Docs and Sheets
    • read-only scope minting (Drive picker, Gmail label picker)
    • the Impersonated Account trim
    • per-code token-refusal copy
    • retry, cache separation, and tolerance of a later release's services
    • the keyless offer and the services the dialog preselects when it is opened by provider id (google-email, from the Integrations page and the chat card)
  • Revert proof: the new tests fail on the pre-fix source.
  • Neighbouring credential, prepare-reconnect, token-resolution and OAuth suites are green. The OpenAPI, CLI and MCP generators are current, and the boundary, client-boundary, utils and comment-hygiene audits pass.
  • Reviewers: focus on backward compatibility. Credentials without delegation store and resolve exactly as before, BigQuery and Vertex AI are unchanged, and an old worker fails closed on a delegated secret. Also check the scope authorization in resolveGoogleWorkloadIdentityToken / delegatedMintScopes.
  • Not yet run against a live Workspace tenant. A staging proof is needed before announcing.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

A keyless (workload identity federation) google-service-account credential
can now opt into domain-wide delegation with an optional `delegation`
({ user, services }) in its keyless configuration. Runs for a delegated
Workspace service (Gmail, Drive, Docs, Sheets, Calendar) exchange Sim's
token at STS, have IAM signJwt the JWT-bearer assertion for the service
account with sub set to the delegated user, and exchange it at
oauth2.googleapis.com/token. The credential acts only as its own user: a
different Impersonated Account is refused before Google is contacted.

Saving a delegated credential mints a delegated token per service and makes
one cheap read as the user; the stray-subject pin probe also checks signJwt.
Tokens are cached per credential, secret version, delegated user, and scopes.

Credentials saved without delegation store exactly the same secret and
resolve exactly as before; BigQuery and Vertex AI keep the service account
token path.
…e service account dialog

The Gmail, Google Drive, Google Docs, Google Sheets, and Google Calendar
integrations now offer the keyless (Workload Identity Federation) mode, with
a Domain-wide delegation picker preselecting the service the dialog was
opened for and a required Workspace user. The dialog lists the scopes to
authorize in the Admin console, and its gcloud commands grant
roles/iam.serviceAccountTokenCreator (which includes signJwt) instead of
roles/iam.workloadIdentityUser when delegation is on. Other Workspace
services keep the JSON key only.
…copes

A keyless credential with domain-wide delegation now signs an assertion only
for the scopes its delegated services authorize, and refuses any other scope
before contacting Google (a Gmail read-only connector, the admin directory
scopes, cloud-platform). A requested read-only scope is minted as the
authorized read-write scope that covers it, so the Drive file picker works
for a credential delegated for Drive, Docs, or Sheets.

The delegated assertion is exchanged through the same transport a JSON key
uses (bounded read, retries on 429 and 5xx within a budget), sharing its list
of diagnostic error codes. Saving checks Drive, Docs, and Sheets, which share
scopes and a read, once, and the pin probe signs for every delegated scope.

A stored secret naming a delegated service a later release adds stays
readable: that service authorizes nothing here, and Google Cloud tokens and
the known services keep working. An unreadable secret fails in the shared
service-account codes.
…econnect

Preparing a reconnect of a keyless Google credential now returns its stored
Workspace user and delegated services to the credential's admin (neither is
secret), and the dialog opens on them, adding the service it was opened for.
Reconnecting no longer silently drops delegation. A dialog opened for a
delegable service requires that service to be delegated.
… for keyless delegation

A read-only Gmail request is minted as the authorized gmail.modify scope, an
Impersonated Account is compared trimmed, and each documented token-endpoint
refusal gets its own copy instead of always pointing at the Admin console.
The stored secret is parsed in one place and the save-time read shares the
POST helper's redirect and timeout guards.
… map

The prepare use case no longer branches on the Google provider: each provider's
reader returns everything a reconnect reopens on. The dialog takes the stored
delegation type from the contract, and one helper says which services a keyless
Google credential serves.
…ns page and chat card

Both entry points pass the OAuth provider id (google-email) where the dialog
compared against service ids (gmail), so Gmail never offered keyless mode
there and a keyless reconnect from chat was refused. The shared helpers and
the dialog now map either id through googleDelegationServiceFor.
@vercel

vercel Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Nov 12, 2026 1:33pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[High impact] The PR appears safe to merge; the latest change fixes the previous documentation finding.

Summary

Adds keyless Google Workspace delegation through IAM signJwt.

  • Keyless Google credentials can act as one Workspace user.
  • Google’s keyless setup offers Workspace delegation and keeps it on reconnect.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Sim token] --> B[Google STS]
  B --> C[IAM signJwt]
  C --> D[Google OAuth token exchange]
  D --> E[Workspace access as the saved user]
Loading

Reviews (3) · Last reviewed commit: "docs(integrations): note the Calendar co..." · Reviewed by Greptile

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 17 files

Confidence score: 3/5

  • The scope matcher in apps/sim/lib/credentials/google-workload-identity.server.ts rejects every Calendar token because credentials authorize calendar while the connector requests calendar.events.readonly. Add an explicit mapping for the read-only scope.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/lib/credentials/google-workload-identity.server.ts">

<violation number="1" location="apps/sim/lib/credentials/google-workload-identity.server.ts:846">
P2: Calendar credentials authorize `calendar`, but the connector requests `calendar.events.readonly`; this matcher finds neither `calendar` nor a mapping and rejects every such token. Map this read-only scope to the authorized `calendar` scope.</violation>
</file>

Turn on auto-fix | Re-trigger cubic

…d calendar.events.readonly

The Calendar connector requests calendar.events.readonly, whose read-write
sibling calendar.events is not what a Calendar delegation authorizes, so every
keyless delegated Calendar connector token was refused. Map it to calendar,
the authorized scope Google documents as covering it.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 17 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 17 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1
waleedlatif1 merged commit 7d5641d into staging Nov 12, 2026
83 checks passed
@waleedlatif1
waleedlatif1 deleted the feat/google-workspace-keyless-dwd branch November 12, 2026 17:02

This branch was successfully deployed

1 active deployment
Preview — 42f378a9 Deployed Nov 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant