fix: use ghinstallation for GitHub App token refresh#116
fix: use ghinstallation for GitHub App token refresh#116abebars wants to merge 3 commits intoConductorOne:mainfrom
Conversation
WalkthroughReplaces manual GitHub App JWT handling with ghinstallation-based App/Installation transports and an oauth2 TokenSource; adds indirect dependencies and tests for App and PAT authentication, token refresh/expiry, and multi-org misconfiguration. Changes
Sequence Diagram(s)sequenceDiagram
participant App as Application
participant GHT as ghinstallation Transport
participant TS as ghinstallationTokenSource
participant GH as GitHub API
participant GQL as GraphQL Client
App->>GHT: Initialize App transport (AppID, PrivateKey[, EnterpriseURL])
App->>TS: Wrap GHT as oauth2.TokenSource
App->>GQL: Create GraphQL client using TS
GQL->>TS: Request token
TS->>GHT: Request installation token
GHT->>GH: Use JWT to request installation token
GH-->>GHT: Return installation token (with expiry)
GHT-->>TS: Provide oauth2.Token
TS->>TS: Cache token until expiry
TS-->>GQL: Return oauth2.Token
note over GHT,TS: On expiry, ghinstallation regenerates JWT and refreshes installation token automatically
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
7248766 to
2d4bfae
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@pkg/connector/connector.go`:
- Around line 267-309: The REST clients appClient and ghClient are not
configured for GitHub Enterprise because only appTransport.BaseURL and
installTransport.BaseURL are set; call client.WithEnterpriseURLs(instanceURL) on
both github.Client instances (appClient and ghClient) when instanceURL is
non-empty and not equal to githubDotCom so their BaseURL fields point at the
enterprise API; locate where appClient is created after
ghinstallation.NewAppsTransport and where ghClient is created after
ghinstallation.New and invoke WithEnterpriseURLs using the same instanceURL
logic as used for appTransport/installTransport, matching the pattern used by
newGitHubClient for PAT auth.
- Around line 394-406: The Token() implementation on ghinstallationTokenSource
returns an oauth2.Token with no Expiry so oauth2.ReuseTokenSource treats it as
non-expiring; update Token() to set the token Expiry (e.g., Expiry: time.Now())
so the oauth2 client will re-evaluate and allow ghinstallation.Transport to
refresh tokens. Modify ghinstallationTokenSource.Token to import time, call
g.transport.Token(context.Background()), and return &oauth2.Token{AccessToken:
token, Expiry: time.Now()} (ensuring use of the ghinstallationTokenSource,
Token(), ghinstallation.Transport and oauth2.Token symbols referenced).
🧹 Nitpick comments (1)
pkg/connector/connector_test.go (1)
90-95: Optional: track the skipped GitHub App test.
Consider linking this to an issue or moving it under an integration test tag so it doesn’t stay skipped indefinitely.
ac67be8 to
1b71e4b
Compare
|
We are actively reviewing this and investigating alternative solutions. |
Thanks @dslick. What are the risks of switching this functionality to a tested framework instead of crafting it manually? |
|
I tested the new changes and they still didn't solve the problem. |
Replace manual JWT handling with ghinstallation/v2 library to fix token expiration issues on long-running syncs. Problem: JWT tokens (10-min expiry) were generated once at startup and reused, causing 401 errors when installation tokens expired. Solution: Use ghinstallation which automatically regenerates JWTs and refreshes installation tokens as needed. Changes: - Add ghinstallation/v2 dependency - Replace appTokenRefresher with ghinstallationTokenSource - Add tests for token refresh behavior - Remove dead code (getClientToken, loadPrivateKeyFromString) Fixes ConductorOne#115 Co-Authored-By: Claude <noreply@anthropic.com>
- Handle Enterprise SAML error in hasSAML() to prevent sync failures when org-level SAML is disabled in favor of Enterprise SAML - Configure Enterprise URLs on appClient and ghClient for GitHub Enterprise instances (addresses CodeRabbit feedback) - Set token Expiry from ghinstallation transport for proper oauth2 token refresh behavior (addresses CodeRabbit feedback) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix errcheck: handle w.Write return values in tests - Fix goconst: extract repeated test URL path to constant - Fix gocritic ifElseChain: add nolint directive (switch inappropriate) - Fix nilerr: rename variable and add nolint for intentional fallback - Fix unused: remove unused getInstallationToken function - Fix gosec G101: add nolint for test constant (not credentials) - Remove unused io import Co-Authored-By: Claude <noreply@anthropic.com>
41cc574 to
be10b21
Compare
Hey @abebars could you please tell me
|
|
|
Hello @abebars , please try with https://github.com/ConductorOne/baton-github/releases/tag/v0.2.7,
|
@Bencheng21 Yeah, Just deployed that. I will report back shortly. Thank you |


Note
🤖 Generated with Claude Code
Fixes #115
Summary
Replace manual JWT handling with
ghinstallation/v2library to fix token expiration issues on long-running syncs. Also fixes Enterprise SAML handling and GitHub Enterprise URL configuration.Problem
When using GitHub App authentication, the connector fails with 401 Unauthorized errors after ~10 minutes because:
appTokenRefresher.jwttokenAdditional issues found in production:
4. REST clients not configured with Enterprise URLs for GitHub Enterprise instances
5. Token expiry not set, causing oauth2 to cache tokens indefinitely
6. Enterprise SAML error crashes sync when org-level SAML is disabled in favor of Enterprise SAML
Solution
Use
github.com/bradleyfalzon/ghinstallation/v2- the officially recommended library by go-github that:Plus additional fixes:
WithEnterpriseURLs()on REST clients for GitHub EnterprisehasSAML()gracefully (return false instead of failing)Changes
ghinstallation/v2dependencyappTokenRefresherwithghinstallationTokenSourcewrapperappClientandghClient(addresses CodeRabbit feedback)Expiryfrom transport for oauth2 refresh (addresses CodeRabbit feedback)hasSAML()to prevent sync failuresgetClientToken,loadPrivateKeyFromString,appTokenRefresher)Testing
Production Validation
This fix has been deployed and validated in production:
Rollback Plan
Revert PR - PAT authentication is unchanged, only GitHub App auth is affected.
Summary by CodeRabbit
New Features
Tests
Chores