feat(auth): support pure service account mode without impersonation#399
Open
carrotRakko wants to merge 1 commit intosteipete:mainfrom
Open
feat(auth): support pure service account mode without impersonation#399carrotRakko wants to merge 1 commit intosteipete:mainfrom
carrotRakko wants to merge 1 commit intosteipete:mainfrom
Conversation
Skip setting cfg.Subject when the subject matches the service account's own client_email. This lets a service account access only resources explicitly shared with it, without requiring Domain-Wide Delegation. Closes steipete#346 ✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
3 tasks
delight-ai-agent
added a commit
to delight-co/finest-grained-auth-proxy
that referenced
this pull request
Mar 3, 2026
## Summary
- Add service account (SA) key file support alongside existing OAuth
keyring credentials
- When a credential entry specifies `sa_key_file` + `account`, fgap
copies the key to gog's expected path
(`~/.config/gogcli/sa-{base64url(email)}.json`) on first use (lazy
provisioning)
- No keyring password or OAuth token needed — the SA accesses only
resources explicitly shared with its email
- Update Dockerfile to use `delight-co/gogcli` fork `v0.12.0-delight.1`
which adds SA pure mode support (upstream PR:
steipete/gogcli#399)
- Add config example for SA credential type
## Changes
| File | What |
|------|------|
| `fgap/plugins/google/credential.py` | SA credential selection + key
provisioning to gog's expected path |
| `fgap/plugins/google/plugin.py` | Health check support for SA
credentials (file existence check) |
| `config.example.json5` | SA credential config example |
| `Dockerfile` | Switch to `delight-co/gogcli` fork with SA pure mode |
| `tests/test_google_credential.py` | 5 new tests for SA credential
selection + provisioning |
| `tests/test_google_health.py` | 3 new tests for SA health check |
## Design decisions
- **`sa_key_file` (path) over inline JSON**: Config stays clean (no
JSON-in-JSON), secrets stay in files, key rotation = file swap
- **Lazy provisioning**: Copy SA key on first `select_credential` call.
Plugin ABC has no startup hook, so sync file copy at selection time is
the simplest approach
- **First-match-wins**: Same ordering semantics as OAuth credentials —
SA and OAuth entries can coexist, first match wins
## Test plan
- [x] All existing tests pass (381 total)
- [x] New SA credential tests (5): selection, provisioning path,
priority, fallthrough, skip invalid
- [x] New SA health check tests (3): valid file, missing file, mixed
OAuth+SA
✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
Co-authored-by: Mitsuyuki Osabe <24588751+carrotRakko@users.noreply.github.com>
2 tasks
delight-ai-agent
added a commit
to delight-co/gogcli
that referenced
this pull request
Mar 3, 2026
## Summary Mirrors upstream PR steipete#399. When a service account is configured via `gog auth service-account set`, the CLI always sets `cfg.Subject` (the JWT `sub` claim), which triggers Domain-Wide Delegation. This makes it impossible to use a service account in "pure" mode — where it accesses only resources explicitly shared with its own email address. This PR skips setting `cfg.Subject` when the provided subject matches the service account's own `client_email`. This enables a common automation pattern: share a Drive folder or Calendar with the SA email, and access only those resources — no DWD required. ## Changes - **`internal/googleapi/service_account.go`** — guard `cfg.Subject` assignment: only set when subject differs from the SA's `client_email` - **`internal/googleapi/service_account_test.go`** — 3 test cases: pure SA mode, impersonation mode, empty subject ## Test plan - [x] `go test ./internal/googleapi/` — all existing + new tests pass - [x] `go build ./...` — compiles cleanly ✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved) Co-authored-by: Mitsuyuki Osabe <24588751+carrotRakko@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a service account is configured via
gog auth service-account set, the CLI always setscfg.Subject(the JWTsubclaim), which triggers Domain-Wide Delegation. This makes it impossible to use a service account in "pure" mode — where it accesses only resources explicitly shared with its own email address.This PR skips setting
cfg.Subjectwhen the provided subject matches the service account's ownclient_email. This enables a common automation pattern: share a Drive folder or Calendar with the SA email, and access only those resources — no DWD required.Changes
internal/googleapi/service_account.go— guardcfg.Subjectassignment: only set when subject differs from the SA'sclient_emailinternal/googleapi/service_account_test.go— 3 test cases: pure SA mode, impersonation mode, empty subjectTest plan
go test ./internal/googleapi/— all existing + new tests passgo build ./...— compiles cleanlyCloses #346
✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)