Skip to content

Commit ecfb288

Browse files
committed
baton-github: refresh app token once it expires
1 parent fe06caf commit ecfb288

File tree

1 file changed

+62
-17
lines changed

1 file changed

+62
-17
lines changed

pkg/connector/connector.go

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -176,17 +176,14 @@ func (gh *GitHub) validateAppCredentials(ctx context.Context) (annotations.Annot
176176
}
177177

178178
// newGitHubClient returns a new GitHub API client authenticated with an access token via oauth2.
179-
func newGitHubClient(ctx context.Context, instanceURL string, accessToken string) (*github.Client, error) {
179+
func newGitHubClient(ctx context.Context, instanceURL string, ts oauth2.TokenSource) (*github.Client, error) {
180180
httpClient, err := uhttp.NewClient(ctx, uhttp.WithLogger(true, ctxzap.Extract(ctx)))
181181
if err != nil {
182182
return nil, err
183183
}
184184

185185
ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient)
186186

187-
ts := oauth2.StaticTokenSource(
188-
&oauth2.Token{AccessToken: accessToken},
189-
)
190187
tc := oauth2.NewClient(ctx, ts)
191188
gc := github.NewClient(tc)
192189

@@ -205,13 +202,24 @@ func New(ctx context.Context, ghc *cfg.Github, appKey string) (*GitHub, error) {
205202
return nil, err
206203
}
207204

208-
var appClient *github.Client
205+
var (
206+
client *github.Client
207+
appClient *github.Client
208+
ts = oauth2.StaticTokenSource(
209+
&oauth2.Token{AccessToken: patToken},
210+
)
211+
)
209212
if jwttoken != "" {
210213
if len(ghc.Orgs) != 1 {
211214
return nil, fmt.Errorf("github-connector: only one org should be specified")
212215
}
213216

214-
appClient, err = newGitHubClient(ctx, ghc.InstanceUrl, jwttoken)
217+
appClient, err = newGitHubClient(ctx,
218+
ghc.InstanceUrl,
219+
oauth2.StaticTokenSource(
220+
&oauth2.Token{AccessToken: jwttoken},
221+
),
222+
)
215223
if err != nil {
216224
return nil, err
217225
}
@@ -224,14 +232,26 @@ func New(ctx context.Context, ghc *cfg.Github, appKey string) (*GitHub, error) {
224232
if err != nil {
225233
return nil, err
226234
}
227-
patToken = token
235+
236+
ts = oauth2.ReuseTokenSource(
237+
&oauth2.Token{
238+
AccessToken: token.GetToken(),
239+
Expiry: token.GetExpiresAt().Time,
240+
},
241+
&appTokenRefresher{
242+
ctx: ctx,
243+
instanceURL: ghc.InstanceUrl,
244+
installationID: installation.GetID(),
245+
jwttoken: jwttoken,
246+
},
247+
)
228248
}
229249

230-
client, err := newGitHubClient(ctx, ghc.InstanceUrl, patToken)
250+
client, err = newGitHubClient(ctx, ghc.InstanceUrl, ts)
231251
if err != nil {
232252
return nil, err
233253
}
234-
graphqlClient, err := newGitHubGraphqlClient(ctx, ghc.InstanceUrl, patToken)
254+
graphqlClient, err := newGitHubGraphqlClient(ctx, ghc.InstanceUrl, ts)
235255
if err != nil {
236256
return nil, err
237257
}
@@ -248,17 +268,14 @@ func New(ctx context.Context, ghc *cfg.Github, appKey string) (*GitHub, error) {
248268
return gh, nil
249269
}
250270

251-
func newGitHubGraphqlClient(ctx context.Context, instanceURL string, accessToken string) (*githubv4.Client, error) {
271+
func newGitHubGraphqlClient(ctx context.Context, instanceURL string, ts oauth2.TokenSource) (*githubv4.Client, error) {
252272
httpClient, err := uhttp.NewClient(ctx, uhttp.WithLogger(true, ctxzap.Extract(ctx)))
253273
if err != nil {
254274
return nil, err
255275
}
256276

257277
ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient)
258278

259-
ts := oauth2.StaticTokenSource(
260-
&oauth2.Token{AccessToken: accessToken},
261-
)
262279
tc := oauth2.NewClient(ctx, ts)
263280

264281
instanceURL = strings.TrimSuffix(instanceURL, "/")
@@ -331,16 +348,44 @@ func findInstallation(ctx context.Context, c *github.Client, orgName string) (*g
331348
return installation, resp, nil
332349
}
333350

334-
func getInstallationToken(ctx context.Context, c *github.Client, id int64) (string, error) {
351+
func getInstallationToken(ctx context.Context, c *github.Client, id int64) (*github.InstallationToken, error) {
335352
token, resp, err := c.Apps.CreateInstallationToken(ctx, id, &github.InstallationTokenOptions{})
336353
if err != nil {
337-
return "", err
354+
return nil, err
338355
}
339356

340357
if resp.StatusCode != http.StatusCreated {
341358
body, _ := io.ReadAll(resp.Body)
342-
return "", fmt.Errorf("GitHub API error: %s", body)
359+
return nil, fmt.Errorf("GitHub API error: %s", body)
343360
}
344361

345-
return token.GetToken(), nil
362+
return token, nil
363+
}
364+
365+
type appTokenRefresher struct {
366+
ctx context.Context
367+
jwttoken string
368+
instanceURL string
369+
installationID int64
370+
}
371+
372+
func (r *appTokenRefresher) Token() (*oauth2.Token, error) {
373+
appClient, err := newGitHubClient(r.ctx,
374+
r.instanceURL,
375+
oauth2.StaticTokenSource(
376+
&oauth2.Token{AccessToken: r.jwttoken},
377+
),
378+
)
379+
if err != nil {
380+
return nil, err
381+
}
382+
383+
token, err := getInstallationToken(r.ctx, appClient, r.installationID)
384+
if err != nil {
385+
return nil, err
386+
}
387+
return &oauth2.Token{
388+
AccessToken: token.GetToken(),
389+
Expiry: token.GetExpiresAt().Time,
390+
}, nil
346391
}

0 commit comments

Comments
 (0)