Summary
On 0.22.5, when an encrypted credentials.enc exists in the config dir, setting GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE has no effect: API calls authenticate as the encrypted-credential account, not the account in the file. This inverts the documented precedence.
AGENTS.md and the README both state that CREDENTIALS_FILE takes precedence over encrypted credentials, with encrypted credentials being the fallback only when the env var is unset:
GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE | Path to OAuth credentials JSON (no default; if unset, falls back to encrypted credentials in ~/.config/gws/)
(README precedence table: GOOGLE_WORKSPACE_CLI_TOKEN = priority 1, GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE = priority 2, encrypted credentials = priority 3.)
Observed precedence is the reverse for priorities 2 vs 3: the encrypted store wins whenever credentials.enc is present, even with CREDENTIALS_FILE explicitly set.
Reproduction
Controlled A/B in an isolated config dir, varying only the presence of credentials.enc. Two distinct accounts (call them A and B); credentials.enc is account A, the credentials file is account B.
# Case 1: config dir has a credentials.enc (account A), written by `gws auth login`
GOOGLE_WORKSPACE_CLI_CONFIG_DIR=/tmp/dir-with-enc \
GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/path/to/accountB-creds.json \
gws drive about get --params '{"fields":"user(emailAddress)"}'
# => returns account A's email (CREDENTIALS_FILE ignored)
# Case 2: identical, but config dir has NO credentials.enc
GOOGLE_WORKSPACE_CLI_CONFIG_DIR=/tmp/dir-without-enc \
GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/path/to/accountB-creds.json \
gws drive about get --params '{"fields":"user(emailAddress)"}'
# => returns account B's email (CREDENTIALS_FILE honored, correct)
credentials.enc present |
CREDENTIALS_FILE set |
Identity returned |
| yes |
yes (account B) |
account A (wrong) |
| no |
yes (account B) |
account B (correct) |
The only difference between the two runs is whether credentials.enc exists. The credentials file is well-formed (type: authorized_user with a valid refresh_token); Case 2 proves it loads and authenticates correctly in isolation. This was reproduced from a freshly gws auth login-written credentials.enc in a pristine GOOGLE_WORKSPACE_CLI_CONFIG_DIR, so it is not stale/migration state.
Expected vs actual
- Expected (per docs): with
CREDENTIALS_FILE set, it wins; credentials.enc is only the fallback when the var is unset.
- Actual:
credentials.enc shadows CREDENTIALS_FILE.
Impact
This is the documented multi-account story: a user with a logged-in default account cannot select an alternate account via CREDENTIALS_FILE, because the default's credentials.enc always wins. The only reliable workaround is an isolated GOOGLE_WORKSPACE_CLI_CONFIG_DIR per account (which has no credentials.enc to shadow the file). Worth noting the failure is silent: it returns another account's data with a 200, rather than erroring, which is a sharp edge for agent use.
Environment
gws 0.22.5 (Homebrew googleworkspace-cli 0.22.5, macOS arm64)
keyring backend (default)
Possible locus
Credential-source selection likely consults the encrypted store before checking the GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE env var (auth.rs / credential_store.rs). The TOKEN (priority 1) path was not tested here.
Filed by an agent (Claude Opus 4.8 via opencode) and verified by a human (the clean-room A/B repro above was run interactively). ✨
Summary
On 0.22.5, when an encrypted
credentials.encexists in the config dir, settingGOOGLE_WORKSPACE_CLI_CREDENTIALS_FILEhas no effect: API calls authenticate as the encrypted-credential account, not the account in the file. This inverts the documented precedence.AGENTS.mdand the README both state thatCREDENTIALS_FILEtakes precedence over encrypted credentials, with encrypted credentials being the fallback only when the env var is unset:(README precedence table:
GOOGLE_WORKSPACE_CLI_TOKEN= priority 1,GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE= priority 2, encrypted credentials = priority 3.)Observed precedence is the reverse for priorities 2 vs 3: the encrypted store wins whenever
credentials.encis present, even withCREDENTIALS_FILEexplicitly set.Reproduction
Controlled A/B in an isolated config dir, varying only the presence of
credentials.enc. Two distinct accounts (call them A and B);credentials.encis account A, the credentials file is account B.credentials.encpresentCREDENTIALS_FILEsetThe only difference between the two runs is whether
credentials.encexists. The credentials file is well-formed (type: authorized_userwith a validrefresh_token); Case 2 proves it loads and authenticates correctly in isolation. This was reproduced from a freshlygws auth login-writtencredentials.encin a pristineGOOGLE_WORKSPACE_CLI_CONFIG_DIR, so it is not stale/migration state.Expected vs actual
CREDENTIALS_FILEset, it wins;credentials.encis only the fallback when the var is unset.credentials.encshadowsCREDENTIALS_FILE.Impact
This is the documented multi-account story: a user with a logged-in default account cannot select an alternate account via
CREDENTIALS_FILE, because the default'scredentials.encalways wins. The only reliable workaround is an isolatedGOOGLE_WORKSPACE_CLI_CONFIG_DIRper account (which has nocredentials.encto shadow the file). Worth noting the failure is silent: it returns another account's data with a200, rather than erroring, which is a sharp edge for agent use.Environment
gws 0.22.5(Homebrewgoogleworkspace-cli0.22.5, macOS arm64)keyringbackend (default)Possible locus
Credential-source selection likely consults the encrypted store before checking the
GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILEenv var (auth.rs/credential_store.rs). TheTOKEN(priority 1) path was not tested here.Filed by an agent (Claude Opus 4.8 via opencode) and verified by a human (the clean-room A/B repro above was run interactively). ✨