Skip to content

fix: refresh OAuth2 tokens in long-running watch/subscribe loops#396

Open
zerone0x wants to merge 1 commit intogoogleworkspace:mainfrom
zerone0x:fix/refresh-token-long-running-loops
Open

fix: refresh OAuth2 tokens in long-running watch/subscribe loops#396
zerone0x wants to merge 1 commit intogoogleworkspace:mainfrom
zerone0x:fix/refresh-token-long-running-loops

Conversation

@zerone0x
Copy link
Contributor

Fixes #392

Summary

  • Refresh OAuth2 tokens inside the pull loops of gmail +watch and events +subscribe by calling auth::get_token() on each iteration, instead of obtaining the token once at startup
  • Also refresh tokens before cleanup operations that run after the long-lived loop exits
  • get_token() uses cached credentials via yup_oauth2 and only contacts the OAuth server when the cached access token has expired, so this adds negligible overhead

Changes

  • src/helpers/gmail/watch.rs: Removed pubsub_token and gmail_token parameters from watch_pull_loop; tokens are now refreshed inside the loop. Cleanup section also refreshes its token.
  • src/helpers/events/subscribe.rs: Removed token parameter from pull_loop; token is now refreshed inside the loop. Cleanup section also refreshes its token.

Test plan

  • cargo check passes
  • cargo test — all 550 tests pass
  • cargo clippy — no warnings
  • Manual: run gws gmail +watch for >1 hour and verify it does not exit with 401
  • Manual: run gws events +subscribe for >1 hour and verify it does not exit with 401

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

The `+watch` and `+subscribe` commands obtained OAuth2 access tokens
once at startup and passed them as static `&str` values into their
pull loops. Since Google access tokens expire after 3600 seconds,
both commands would exit with a 401 error after ~1 hour.

Fix by calling `auth::get_token()` on each loop iteration instead of
once before the loop. The underlying `yup_oauth2` authenticator uses
cached credentials and only contacts the OAuth server when the current
access token has expired, so this adds negligible overhead. Also
refresh the token before cleanup operations that run after the
potentially long-lived loop.

Fixes googleworkspace#392

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@changeset-bot
Copy link

changeset-bot bot commented Mar 11, 2026

⚠️ No Changeset found

Latest commit: 4ff80d6

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

@googleworkspace-bot googleworkspace-bot added the area: core Core CLI parsing, commands, error handling, utilities label Mar 11, 2026
@google-cla
Copy link

google-cla bot commented Mar 11, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
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 addresses an issue where long-running watch and subscribe operations for Gmail and events would fail after approximately one hour due to expired OAuth2 tokens. The changes introduce a robust token refresh mechanism, ensuring that access tokens are renewed dynamically within the application's main loops and during subsequent cleanup phases. This significantly improves the stability and reliability of these long-lived processes without incurring substantial overhead, as the underlying authentication library efficiently handles token caching.

Highlights

  • OAuth2 Token Refresh: Implemented OAuth2 token refreshing within long-running gmail +watch and events +subscribe loops to prevent 401 errors due to token expiry.
  • Dynamic Token Management: Ensured tokens are refreshed on each iteration of the pull loops, leveraging yup_oauth2's caching mechanism for efficient token renewal.
  • Cleanup Operation Reliability: Added token refresh mechanisms to cleanup operations that execute after the main loops exit, ensuring successful resource deletion.
Changelog
  • src/helpers/events/subscribe.rs
    • Modified the pull_loop function signature to remove the token parameter, as tokens are now fetched internally.
    • Introduced a token refresh call (auth::get_token) at the beginning of each pull_loop iteration.
    • Updated the cleanup logic to refresh the OAuth2 token immediately before making API calls to delete Pub/Sub resources.
    • Adjusted bearer_auth calls to use the newly refreshed token.
  • src/helpers/gmail/watch.rs
    • Modified the watch_pull_loop function signature to remove pubsub_token and gmail_token parameters.
    • Integrated token refresh calls for both Pub/Sub and Gmail scopes at the start of each watch_pull_loop iteration.
    • Updated the cleanup section to refresh the Pub/Sub token before deleting associated resources.
    • Adjusted bearer_auth calls to use the dynamically refreshed tokens.
Activity
  • cargo check passed successfully.
  • All 550 cargo test cases passed.
  • cargo clippy reported no warnings.
  • Manual testing for gws gmail +watch and gws events +subscribe running for over an hour is pending verification.
  • The pull request was co-authored by Claude Opus 4.6.
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 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 counter productive. 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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
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

The pull request refactors token management in both Pub/Sub subscription and Gmail watch functionalities. Previously, tokens were passed into long-running pull loops, risking expiration. The changes introduce on-demand token refreshing within these loops and during cleanup operations, ensuring that API calls always use valid, non-expired tokens. This is achieved by removing token parameters from the pull_loop and watch_pull_loop functions and instead calling auth::get_token at the beginning of each iteration or before cleanup, which efficiently retrieves a fresh token when needed.

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

Labels

area: core Core CLI parsing, commands, error handling, utilities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: gmail +watch and events +subscribe exit after ~1 hour due to expired access token

2 participants