Skip to main content
← Back to list
01Issue
BugShippedExtensions
Assigneesstack72

Relationships

#1275 gcp _lib: unconditional x-goog-user-project header causes USER_PROJECT_DENIED (403) for service accounts without the serviceUsageConsumer role

Opened by ryan_0zxv · 7/19/2026· Shipped 7/19/2026

Summary

_lib/gcp.ts request() always sets x-goog-user-project: <projectId> when a project ID is known (lines ~413 and ~432 in 2026.07.18.1). For service-account credentials this forces the caller-pays consumer-project path, which requires the service account to hold [HOST-1] on that project. A plain service account created with no IAM roles — sufficient for e.g. read-only Sheets access via file sharing — gets 403 USER_PROJECT_DENIED on every call.

This may be by-design for APIs that genuinely require a quota project, but for APIs where the SA's own project is the default quota project the header adds a role requirement without adding function.

Environment

  • @swamp/gcp/sheets 2026.07.18.1 (shared _lib/gcp.ts)
  • swamp CLI 20260718.081020.0, macOS arm64
  • Auth: service-account JSON (credentialsJson global), SA has NO IAM roles; target sheet shared to the SA as Viewer; Sheets API enabled on the SA's own project

Reproduction

With the header (stock _lib/gcp.ts), a values get against a sheet shared to the SA:

$ swamp model @.../spreadsheets-values method run get values-test --arg 'identifier=Sheet1!A1:B2'
Read failed (403): { "error": { "code": 403, "message": "Caller does not have
required permission to use project <project>. Grant the caller the
roles/serviceusage.serviceUsageConsumer role..." ,
"reason": "USER_PROJECT_DENIED" ... }

Control — identical call with the two header assignments removed from a local copy of _lib/gcp.ts, nothing else changed:

$ swamp model @.../spreadsheets-values method run get values-test --arg 'identifier=Sheet1!A1:B2'
Method "get" completed  (values returned)

Suggested resolution

  • Send the header only when a quota project is explicitly configured (e.g. a dedicated quotaProject global argument), matching google-auth-library semantics where user-project is opt-in
  • Or omit it for service-account credentials, whose own project is the default quota project

Upstream repository: https://github.com/swamp-club/swamp-extensions

Environment

  • Extension: @swamp/gcp/sheets@2026.07.18.1
  • swamp: 20260718.081020.0-sha.fc14abbd
  • OS: darwin (aarch64)
  • Deno: 2.8.3
  • Shell: /bin/zsh
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 9 MOREREVIEW+ 4 MOREPR_MERGED+ 1 MORENOTIFICATION_SKIPPED

Shipped

7/19/2026, 9:30:00 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack727/19/2026, 8:17:59 PM

Sign in to post a ripple.