You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A revoked per-owner GitHub token wipes the provider's working credentials, while the bad owner token stays in place #297
MakeGitHubRequestAsync(name, action, owner) in BuildMonitor/Providers/GitHub.cs uses the owner's override token when owner.HasToken is true. But on an AuthorizationException, or a 403 that isn't a rate limit (around lines 701-706 and 716-721), it always calls BuildProvider.OnAuthenticationFailure() (BuildProvider.cs:269). That clears the provider-level AccountId and Token, whichever credential the request actually used.
Why it matters
An owner-scoped failure takes every other owner offline. One owner with an expired or revoked override token clears the global provider credentials.
The broken token is never removed. The owner token that caused the failure stays in the store, so HasValidCredentials(owner) stays true and that owner keeps sending requests that get 401 every cycle.
A single 403 erases the global token. One request the token isn't permitted to make, such as a workflow dispatch on a repository where the token lacks actions: write, is treated the same way.
Reproduction (ran against an in-memory TokenStorage)
Set a provider token and an owner override token.
Call MakeGitHubRequestAsync with that owner and an action that throws AuthorizationException.
Result: the provider token is empty and the owner token is still set.
Expected: the owner token is cleared (or flagged) and the provider token is untouched.
Suggested fix / acceptance criteria
When the failing request used owner.HasToken, clear only owner.Token, set that owner's status, and leave the provider credentials alone.
Treat a non-rate-limit 403 as a per-request error (report it on that action) rather than as a credential failure.
Priority: High. One owner with an expired override token clears the global provider credentials and takes every other owner offline, while its own bad token stays in place and keeps getting 401s. A single non-rate-limit 403, such as a dispatch without actions: write, also wipes the global token.
Area / suggested assignee: The auth-failure handling in GitHub.MakeGitHubRequestAsync and BuildProvider.OnAuthenticationFailure. Maintainer: @matt-edmondson.
Next steps: When the failing request used owner.HasToken, clear or flag only that owner's token. Treat a non-rate-limit 403 as a per-action error, not a credential failure. Add tests for both paths against an in-memory TokenStorage.
Activity
matt-edmondson commentedon Sep 26, 2026
Triage
actions: write, also wipes the global token.GitHub.MakeGitHubRequestAsyncandBuildProvider.OnAuthenticationFailure. Maintainer: @matt-edmondson.owner.HasToken, clear or flag only that owner's token. Treat a non-rate-limit 403 as a per-action error, not a credential failure. Add tests for both paths against an in-memoryTokenStorage.Generated by Claude Code