-
Notifications
You must be signed in to change notification settings - Fork 81
GITHUB_TOKEN env var not updated after credential refresh, breaking all gh CLI operations #1135
Description
Problem
When GITHUB_TOKEN expires mid-session, calling refresh_credentials (the MCP tool) refreshes the backend credentials — the git credential helper (/tmp/git-credential-ambient) returns a valid fresh token — but the GITHUB_TOKEN shell environment variable retains the stale value. Since the gh CLI prioritizes GITHUB_TOKEN over all other credential sources, every gh command fails with 401 Bad credentials even though valid credentials are available.
This affects all gh operations: gh pr create, gh api, gh repo list, gh issue view, gh search issues, etc.
Steps to reproduce
- Start a session with GitHub integration connected
- Wait for the
GITHUB_TOKENto expire (or observe it mid-session) - Call
refresh_credentialsMCP tool — it reports success - Run
gh auth status— fails with "The token in GITHUB_TOKEN is invalid" - Verify the credential helper has a fresh token:
FRESH_TOKEN=$(printf 'protocol=https\nhost=github.com\n\n' | git credential fill 2>/dev/null | grep '^password=' | cut -d= -f2) echo "Token length: ${#FRESH_TOKEN}" # Returns 40, confirming a token exists
- Override the env var inline — works:
GITHUB_TOKEN="$FRESH_TOKEN" gh auth status # Succeeds
- But the next
ghcommand in a new shell invocation fails again becauseGITHUB_TOKENis re-injected with the stale value
Expected behavior
After refresh_credentials is called, gh commands should work. Either:
- The
GITHUB_TOKENenv var should be updated to the fresh token, or - The stale
GITHUB_TOKENshould be cleared soghfalls through to the credential helper
Actual behavior
GITHUB_TOKENretains the expired value across all shell invocationsghreads the stale env var and returns 401 on every call- The credential helper has a valid token but
ghnever consults it becauseGITHUB_TOKENtakes precedence
Impact
- PR creation fails (both
gh pr createand searching for existing forks/issues) - No
gh apicalls work, blocking any GitHub API interaction - Workaround exists (inline
GITHUB_TOKEN=fresh gh ...per command) but is fragile since fresh tokens also appear to be short-lived
Workaround
The updated PR skill in workflows/bugfix/.claude/skills/pr/SKILL.md documents this workaround:
FRESH_TOKEN=$(printf 'protocol=https\nhost=github.com\n\n' | git credential fill 2>/dev/null | grep '^password=' | cut -d= -f2)
GITHUB_TOKEN="$FRESH_TOKEN" gh auth statusThis works for individual commands but must be repeated for each invocation because the shell env is re-initialized with the stale token each time.
Relationship to #935
Issue #935 addresses the type of token (installation tokens lack cross-fork PR permissions). This issue addresses the delivery of the token (the env var goes stale mid-session). They are complementary — even with #935's proposed OAuth user-to-server tokens, those tokens would still go stale if the env var isn't synced after refresh.
This issue was filed by Claude Code under the supervision of Bill Murdock.