mirror of
https://github.com/vercel/chat.git
synced 2026-09-14 18:32:29 +08:00
270b1c2592
## Summary When a Google Chat app's connection setting **Authentication audience** is set to **HTTP endpoint URL** (Google's recommended option for HTTP-hosted apps that aren't behind Cloud Run IAM, see [Verify requests from Google Chat][1]), the bearer token Google sends is an OIDC ID token whose `aud` is the endpoint URL — not the GCP project number. The adapter previously only verified against `googleChatProjectNumber`, so URL-audience tokens always failed with `401 Unauthorized` and direct webhooks silently broke for any app configured this way. This change makes the adapter verify direct-webhook JWTs against `googleChatProjectNumber` and/or `endpointUrl`, accepting either when both are configured (handy for multi-env setups that mix the two modes). The constructor's fail-closed check accepts an explicit `endpointUrl` as a valid direct-webhook verifier alongside `googleChatProjectNumber`, `pubsubAudience`, and `disableSignatureVerification`. [1]: https://developers.google.com/workspace/chat/verify-requests-from-chat ## Behavior | Config | Direct-webhook `aud` accepted | | ----------------------------------------------------------- | --------------------------------- | | `googleChatProjectNumber` only (current behavior) | project number | | `endpointUrl` only (**new**) | endpoint URL | | Both `googleChatProjectNumber` and `endpointUrl` (**new**) | either | | Neither, no `pubsubAudience`, no `disableSignatureVerification` | constructor throws (unchanged) | ### Security note Auto-detected endpoint URLs (the value `handleWebhook` falls back to from the incoming `request.url` when `endpointUrl` is not configured) are intentionally **not** promoted to verifier status. Treating an auto-detected URL as a valid audience would let any caller bypass verification by hitting the bot at a URL of their choice. A new `endpointUrlIsAudience` flag captures whether the caller explicitly configured `endpointUrl`, and only that case enables URL-based verification. A regression test guards this. ## Implementation - `verifyBearerToken` accepts `string | string[]` (`OAuth2Client.verifyIdToken` already supports both). - `handleWebhook` builds `directAudiences = [projectNumber, explicitEndpointUrl].filter(Boolean)` and passes a single string when only one verifier is configured (to preserve the prior call shape) or an array when both are. - Docs updated in `apps/docs/content/adapters/official/google-chat.mdx`: describe both authentication-audience modes and document `endpointUrl` as an accepted verifier. - Changeset: `@chat-adapter/gchat: patch`. ## Test plan - [x] `pnpm --filter @chat-adapter/gchat test` — 250/250 pass (5 new tests). - [x] `pnpm typecheck` — 33/33 tasks pass. - [x] `pnpm check` (Ultracite/Biome) clean. - [x] `pnpm konsistent` clean. - [x] Validated end-to-end against a real Google Chat app configured with "HTTP endpoint URL" as authentication audience: webhooks that previously 401'd now verify and process correctly. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>