Skip to content

fix(auth): clear token cache after login#808

Open
Lubrsy706 wants to merge 3 commits into
googleworkspace:mainfrom
Lubrsy706:fix/auth-login-clear-token-cache
Open

fix(auth): clear token cache after login#808
Lubrsy706 wants to merge 3 commits into
googleworkspace:mainfrom
Lubrsy706:fix/auth-login-clear-token-cache

Conversation

@Lubrsy706
Copy link
Copy Markdown

Summary

  • clear OAuth and service-account token caches after a successful gws auth login
  • reuse the same cache-clearing helper from auth logout
  • invalidate the cached account timezone on login as well as logout

Why

After re-authenticating with different scopes or a different account, the existing token_cache.json can still contain an access token minted from the previous credentials. That makes auth status show the new scopes while API calls keep failing with stale-token permissions until the user manually deletes the cache.

Fixes #764.

Tests

  • cargo fmt --check
  • cargo test -p google-workspace-cli clear_token_caches_removes_user_and_service_account_caches
  • cargo check -p google-workspace-cli
  • git diff --check

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 15, 2026

⚠️ No Changeset found

Latest commit: 5dd36e1

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request improves the authentication lifecycle by ensuring that token caches are properly invalidated upon login. By reusing a centralized cleanup mechanism, the changes prevent issues where stale access tokens or cached account data persist after a user re-authenticates with different scopes or accounts, resolving a known issue with API call failures.

Highlights

  • Token Cache Management: Introduced a centralized helper function to clear both user and service account token caches, ensuring consistency across login and logout operations.
  • Login Behavior: Updated the login flow to automatically invalidate token caches and account timezone information, preventing the use of stale credentials after re-authentication.
  • Testing: Added a new unit test to verify that the token cache clearing logic correctly removes the expected files.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Generative AI Prohibited Use Policy, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request centralizes token cache management by introducing a clear_token_caches helper function, which is now utilized during both login and logout processes to prevent the use of stale credentials. Review feedback highlighted security concerns regarding unsanitized error messages in terminal output and potential TOCTOU race conditions in file removal logic; it is recommended to sanitize output and handle file deletion more robustly by catching specific I/O errors instead of pre-checking existence.

Comment on lines +352 to +363
fn clear_token_caches() -> Result<Vec<PathBuf>, GwsError> {
let mut removed = Vec::new();
for path in token_cache_paths() {
if path.exists() {
std::fs::remove_file(&path).map_err(|e| {
GwsError::Validation(format!("Failed to remove {}: {e}", path.display()))
})?;
removed.push(path);
}
}
Ok(removed)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The error message generated when failing to remove a cache file is not sanitized, which violates the general rule to prevent escape sequence injection in terminal output. Additionally, using path.exists() followed by remove_file introduces a TOCTOU (time-of-check to time-of-use) race condition. It is more robust to attempt the removal directly and handle the NotFound error case. Please acknowledge and document potential TOCTOU race conditions as a known limitation if a full mitigation (e.g., using openat(O_NOFOLLOW)) is considered out of scope.

fn clear_token_caches() -> Result<Vec<PathBuf>, GwsError> {
    let mut removed = Vec::new();
    for path in token_cache_paths() {
        match std::fs::remove_file(&path) {
            Ok(_) => removed.push(path),
            Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
            Err(e) => {
                return Err(GwsError::Validation(crate::output::sanitize_for_terminal(
                    &format!("Failed to remove {}: {e}", path.display()),
                )));
            }
        }
    }
    Ok(removed)
}
References
  1. Sanitize error strings printed to the terminal to prevent escape sequence injection.
  2. When implementing file path validation, acknowledge and document potential Time-of-check to time-of-use (TOCTOU) race conditions as a known limitation if a full mitigation (e.g., using openat(O_NOFOLLOW)) is considered out of scope.

Comment on lines 1485 to 1490
if path.exists() {
std::fs::remove_file(path).map_err(|e| {
GwsError::Validation(format!("Failed to remove {}: {e}", path.display()))
})?;
removed.push(path.display().to_string());
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

This loop lacks error string sanitization and contains a TOCTOU race condition. Following the pattern suggested for the clear_token_caches helper, you should sanitize the error message and handle the NotFound case explicitly instead of checking for existence beforehand. Note that potential TOCTOU race conditions should be acknowledged as a known limitation if full mitigation is out of scope.

        match std::fs::remove_file(path) {
            Ok(_) => removed.push(path.display().to_string()),
            Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
            Err(e) => {
                return Err(GwsError::Validation(crate::output::sanitize_for_terminal(
                    &format!("Failed to remove {}: {e}", path.display()),
                )));
            }
        }
References
  1. Sanitize error strings printed to the terminal to prevent escape sequence injection.
  2. When implementing file path validation, acknowledge and document potential Time-of-check to time-of-use (TOCTOU) race conditions as a known limitation if a full mitigation (e.g., using openat(O_NOFOLLOW)) is considered out of scope.

@googleworkspace-bot
Copy link
Copy Markdown
Collaborator

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces centralized logic for clearing token caches during the login and logout processes. It adds helper functions token_cache_paths, remove_file_if_exists, and clear_token_caches to auth_commands.rs, along with unit tests for these new utilities. The review feedback highlights a potential issue where using the ? operator on clear_token_caches during login could cause the command to report failure even if credentials were saved successfully. It is recommended to handle cache-clearing errors gracefully to avoid a confusing user experience.


// Access tokens in the cache may belong to the previous account or scope set.
// Force the next API call to mint a token from the newly saved credentials.
let _ = clear_token_caches()?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using the ? operator here causes the entire login command to fail if clearing the token caches fails (e.g., due to a permission issue). However, at this point, the new credentials have already been successfully encrypted and saved to disk (lines 668-669). Failing the command here prevents the success message and account details from being printed (lines 676-687), which leads to a confusing user experience where the tool reports failure despite the authentication actually succeeding.

Since clearing the cache is a secondary cleanup step, it is better to handle any errors gracefully (e.g., by logging a warning) so that the login process can complete successfully and the user is informed of their current status.

    if let Err(e) = clear_token_caches() {
        eprintln!("Warning: {e}");
    }

@googleworkspace-bot
Copy link
Copy Markdown
Collaborator

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces logic to clear token caches during both login and logout processes to ensure that stale access tokens do not persist. It adds helper functions token_cache_paths, remove_file_if_exists, and clear_token_caches to handle the removal of user and service account token caches, including error message sanitization. The handle_login_inner and handle_logout functions were updated to utilize these helpers, and new unit tests were included to verify the functionality. I have no feedback to provide.

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.

Token cache invalidation

2 participants