Skip to content

fix(auth): clear token caches after login so new scopes take effect - #959

Draft
phatmandrake wants to merge 3 commits into
googleworkspace:mainfrom
phatmandrake:fix/clear-token-cache-after-login
Draft

phatmandrake wants to merge 3 commits into
googleworkspace:mainfrom
phatmandrake:fix/clear-token-cache-after-login

Conversation

@phatmandrake

Copy link
Copy Markdown

Description

gws auth login saved the new credentials but never touched token_cache.json or sa_token_cache.json. The token cache is keyed by scope set (token_storage.rs cache_key), and auth::get_token serves a still-valid cached token without refreshing, so any method already called before the re-login kept receiving the access token minted under the previous grant, which lacked the newly added scopes, until it expired (up to an hour). Users saw a persistent 403 Request had insufficient authentication scopes while gws auth status showed the new scopes and credentials.enc had a fresh timestamp.

This change removes both cache files right after the new credentials are saved in handle_login_inner, and invalidates the cached timezone as auth logout already does. If a cache file exists but cannot be removed, login now fails with an explicit error instead of reporting success while stale tokens remain in use. handle_logout is unchanged.

Fixes #764
Fixes #876

Earlier attempts #796 and #808 implemented the same idea and were closed by the stale workflow without review.

Scope note: handle_logout and the undecryptable-credentials recovery path in auth.rs each remove the same two cache files with their own loop (logout checks exists() first, the recovery path is best-effort). This PR deliberately does not touch them, to keep the fix minimal; happy to follow up with a change that routes both through clear_token_caches if maintainers want that.

Reproduction (before):

  1. gws auth login --scopes <set without chat.messages.readonly>
  2. gws chat spaces messages list --params '{"parent":"spaces/<id>","pageSize":1}' → 403 (expected), writes token_cache.json
  3. gws auth login --scopes <same set plus chat.messages.readonly> → login succeeds, auth status lists the new scope
  4. Step 2 again → still 403 until the cached token expires

Verification (after, this branch, macOS 26, keyring backend): same four steps with the patched binary. After step 3 the config directory no longer contains token_cache.json, and step 4 returns messages immediately (credentials written 19:47:06, fresh cache minted by the next call at 19:50:48).

Dry Run Output:

// Not applicable: this change affects the auth login flow, not a request body.

Checklist:

  • My code follows the AGENTS.md guidelines (no generated google-* crates).
  • I have run cargo fmt --all to format the code perfectly.
  • I have run cargo clippy -- -D warnings and resolved all warnings. (The one remaining error, collapsible_match in helpers/script.rs:173, is present on main with rustc 1.95 and is outside this change.)
  • I have added tests that prove my fix is effective or that my feature works. (clear_token_caches_removes_both_cache_files, clear_token_caches_is_noop_when_files_absent, clear_token_caches_errors_when_cache_cannot_be_removed; 704 tests pass.)
  • I have provided a Changeset file (e.g. via pnpx changeset) to document my changes. (.changeset/clear-token-cache-after-login.md, patch.)

`gws auth login` saved the new credentials but left token_cache.json and
sa_token_cache.json in place. The cache is keyed by scope set, so any method
called before the re-login kept receiving the access token minted under the
previous grant, which still lacked the new scopes, until it expired (up to
an hour). Users saw a persistent 403 "Request had insufficient
authentication scopes" while `auth status` showed the new scopes.

Remove both cache files right after the new credentials are saved, and
invalidate the cached timezone as logout already does. If a cache file
exists but cannot be removed, login now fails with an explicit error
instead of reporting success while stale tokens remain in use.

Fixes googleworkspace#764
Fixes googleworkspace#876
@changeset-bot

changeset-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 616c10a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@phatmandrake
phatmandrake marked this pull request as draft October 15, 2026 01:56
Logout and login now share one helper, clear_token_caches, which returns the
paths it actually removed. This removes the check-then-delete race in logout.
The decrypt-failure recovery path in auth.rs keeps its warn-and-continue loop
on purpose.
The test encrypts and decrypts through config_dir() without the serial
lock, so a test that switches GOOGLE_WORKSPACE_CLI_CONFIG_DIR under the
lock can change the key file between its two reads. Seven neighbouring
tests already carry the attribute.
@googleworkspace-bot

Copy link
Copy Markdown
Collaborator

/gemini review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants