Summary
After re-authenticating (gws auth login -s drive,docs), gws continued returning 403 insufficient authentication scopes on every Drive API call, while Gmail-scoped calls succeeded fine throughout. The login command's own output correctly listed https://www.googleapis.com/auth/drive as a granted scope, and ~/.config/gws/credentials.enc had a fresh timestamp — but the actual Drive API calls kept failing as if that scope had never been granted.
Environment
gws version: 0.11.1 (@googleworkspace/cli)
- macOS 15.7.3 (Build 24G419)
- Auth method: OAuth2, installed/desktop client (
redirect_uris: ["http://localhost"])
- Keyring backend:
keyring
What was ruled out before finding the real cause
Extensive troubleshooting confirmed this was not caused by any of the following (each checked directly):
- OAuth consent screen scope configuration (Drive API confirmed
ENABLED via gcloud services list)
- OAuth consent screen test users list (account confirmed present)
- A stray local process holding a port from a previous
gws auth login invocation (found and killed one, no change)
- A full OS reboot (no change — rules out any in-memory/process-level caching)
client_secret.json validity (if this were invalid, login itself would fail with invalid_client, not succeed and then fail on API calls — and other-scoped calls, e.g. Gmail, worked fine throughout)
Multiple full gws auth login -s drive,docs re-runs across this window, including after switching to a different Google account and back, did not resolve the issue.
Root cause (as best diagnosed)
~/.config/gws/ contains two separate local token/credential stores:
credentials.enc (encrypted, gets a fresh timestamp on every gws auth login)
token_cache.json (binary — not actually JSON despite the extension/name; failed UTF-8 decode when inspected)
A normal gws auth login re-auth appears to refresh credentials.enc but not fully invalidate/replace whatever state token_cache.json holds (or vice versa — the exact read/write interaction between the two wasn't fully traced from the outside). The practical symptom: the CLI looks like it completed a fresh login with the requested scope, but the token actually used for API calls doesn't carry that scope.
Workaround that fixed it
Manually deleting the cached credential/token state (while preserving the app config) and then doing a completely fresh login resolved the issue immediately:
rm ~/.config/gws/credentials.enc ~/.config/gws/token_cache.json
rm -rf ~/.config/gws/cache/* # cached API discovery docs, unrelated to auth but safe to clear too
gws auth login -s drive,docs
(client_secret.json and .encryption_key were left untouched — those are the app identity/encryption key, not per-session state.)
Immediately after this, gws drive files list succeeded and returned real results.
Suggested fix
gws auth login (or a new --fresh/--clear-cache flag) should fully clear all local token/credential state before starting a new interactive login, rather than leaving a possibly-stale secondary cache (token_cache.json) in place alongside a freshly-written credentials.enc. Right now the only way to force a truly clean re-auth is to know to manually delete files inside ~/.config/gws/ — there's no documented or CLI-exposed way to do this.
Happy to provide more detail if useful — this took a couple hours of systematic elimination to track down, so hopefully this saves someone else the trouble.
Summary
After re-authenticating (
gws auth login -s drive,docs),gwscontinued returning403 insufficient authentication scopeson every Drive API call, while Gmail-scoped calls succeeded fine throughout. The login command's own output correctly listedhttps://www.googleapis.com/auth/driveas a granted scope, and~/.config/gws/credentials.enchad a fresh timestamp — but the actual Drive API calls kept failing as if that scope had never been granted.Environment
gwsversion: 0.11.1 (@googleworkspace/cli)redirect_uris: ["http://localhost"])keyringWhat was ruled out before finding the real cause
Extensive troubleshooting confirmed this was not caused by any of the following (each checked directly):
ENABLEDviagcloud services list)gws auth logininvocation (found and killed one, no change)client_secret.jsonvalidity (if this were invalid, login itself would fail withinvalid_client, not succeed and then fail on API calls — and other-scoped calls, e.g. Gmail, worked fine throughout)Multiple full
gws auth login -s drive,docsre-runs across this window, including after switching to a different Google account and back, did not resolve the issue.Root cause (as best diagnosed)
~/.config/gws/contains two separate local token/credential stores:credentials.enc(encrypted, gets a fresh timestamp on everygws auth login)token_cache.json(binary — not actually JSON despite the extension/name; failed UTF-8 decode when inspected)A normal
gws auth loginre-auth appears to refreshcredentials.encbut not fully invalidate/replace whatever statetoken_cache.jsonholds (or vice versa — the exact read/write interaction between the two wasn't fully traced from the outside). The practical symptom: the CLI looks like it completed a fresh login with the requested scope, but the token actually used for API calls doesn't carry that scope.Workaround that fixed it
Manually deleting the cached credential/token state (while preserving the app config) and then doing a completely fresh login resolved the issue immediately:
(
client_secret.jsonand.encryption_keywere left untouched — those are the app identity/encryption key, not per-session state.)Immediately after this,
gws drive files listsucceeded and returned real results.Suggested fix
gws auth login(or a new--fresh/--clear-cacheflag) should fully clear all local token/credential state before starting a new interactive login, rather than leaving a possibly-stale secondary cache (token_cache.json) in place alongside a freshly-writtencredentials.enc. Right now the only way to force a truly clean re-auth is to know to manually delete files inside~/.config/gws/— there's no documented or CLI-exposed way to do this.Happy to provide more detail if useful — this took a couple hours of systematic elimination to track down, so hopefully this saves someone else the trouble.