fix(auth): persist refresh_token so OAuth survives across restarts#35
Open
BrentBaccala wants to merge 1 commit into
Open
fix(auth): persist refresh_token so OAuth survives across restarts#35BrentBaccala wants to merge 1 commit into
BrentBaccala wants to merge 1 commit into
Conversation
The server loses authentication roughly every hour because it never reliably retains a refresh_token. Two independent causes, both matching upstream GongRzhe/Gmail-MCP-Server Issue GongRzhe#50: 1. generateAuthUrl() lacked `prompt: 'consent'`. With only `access_type: 'offline'`, Google returns a refresh_token solely on the first consent for a given (user, OAuth client) pair; subsequent auth flows return an access_token only. Adding `prompt: 'consent'` forces a re-prompt, so a refresh_token is always returned. 2. There was no `on('tokens')` listener, so google-auth-library's silent access_token rotation updated only the in-memory client — on the next process start the server re-read a now-stale token from disk. The listener merges rotated tokens back into credentials.json, preserving the refresh_token (and the existing `{ tokens, scopes }` credential wrapper), and writes the file with mode 0600. Together these make the credential durable across both access_token expiry and process restarts. Ref: GongRzhe#50 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The server loses authentication roughly every hour and requires a manual re-auth. The root cause is that it never reliably retains a
refresh_token, so once the ~1-houraccess_tokenexpires there is nothing to refresh from. This matches upstream GongRzhe/Gmail-MCP-Server Issue #50.There are two independent contributing bugs:
generateAuthUrl()omitsprompt: 'consent'. With onlyaccess_type: 'offline', Google returns arefresh_tokensolely on the first consent for a given (user, OAuth client) pair. Every subsequent auth flow is treated as silent re-authentication and returns anaccess_tokenonly — and the auth handler then overwritescredentials.jsonwith that refresh-token-less response, discarding any priorrefresh_token.No
on('tokens')listener.google-auth-libraryrotates theaccess_tokensilently in memory, but nothing persists the rotated token to disk. On the next process start the server re-reads a now-stale token.Fix
prompt: 'consent'togenerateAuthUrl()so Google always re-prompts and therefore always returns arefresh_token.oauth2Client.on('tokens', …)listener that merges rotated tokens back intocredentials.json, preserving therefresh_tokenand the existing{ tokens, scopes }credential wrapper, written with mode0600.Together these make the credential durable across both
access_tokenexpiry and process restarts.Testing
npm run build(tsc) compiles clean on Node 25.credentials.jsonis written with a populatedtokens.refresh_token, and the MCP server connects and lists labels end-to-end.maintip; the change is isolated tosrc/index.ts(+20 lines) and does not touch the recently-added draft-lifecycle / phishing tools.This PR was researched and written by an AI assistant (Claude) on behalf of Brent Baccala (cosine@freesoft.org), based on source analysis of
src/index.tsand a reproduced ~hourly auth-drop on this fork. The fix mirrors the root-cause analysis in upstream Issue GongRzhe#50.