Skip to content

gws auth login can silently leave a stale/split token cache, causing 403 insufficient authentication scopes after re-auth #876

Description

@kbroughton

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions