mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2026-02-13 21:00:00 +00:00
Fix OAuth token refresh in webhook handling for Bitbucket and GitHub (#6059)
## Summary Fixes #5590 Fixes #5713 This PR fixes an issue where webhook handling fails with "failure to parse hook" error when the user's OAuth access token has expired. The root cause is that the Bitbucket and GitHub forge implementations make API calls during webhook processing without first refreshing the OAuth token. ## Problem When a webhook arrives from Bitbucket or GitHub, the `Hook()` function (and its helper functions) make API calls to fetch additional data (changed files, repo info, etc.). These API calls use the stored OAuth access token, which may have expired. **Before this fix:** 1. Webhook arrives 2. `Hook()` makes API calls with potentially expired token 3. API call fails with "OAuth2 access token expired" 4. Error bubbles up as HTTP 400 "failure to parse hook" 5. `forge.Refresh()` is called later in `PostHook()` - but it's too late **Example error from logs:** `failure to parse hook error="OAuth2 access token expired. Use your refresh token to obtain a new access token."` ## Solution Add `forge.Refresh()` calls before making API calls in the webhook handling code paths. This follows the same pattern already used by: - Bitbucket Data Center forge (`server/forge/bitbucketdatacenter/bitbucketdatacenter.go`) - Other code paths like `pipeline.Create()`, `cron.go`, etc. ### Changes **Bitbucket** (`server/forge/bitbucket/bitbucket.go`): - Added `forge.Refresh()` in `Hook()` before API calls **GitHub** (`server/forge/github/github.go`): - Added `forge.Refresh()` in `loadChangedFilesFromPullRequest()` - Added `forge.Refresh()` in `getTagCommitSHA()` - Added `forge.Refresh()` in `loadChangedFilesFromCommits()` ## Testing - All existing Bitbucket and GitHub forge tests pass - Tested in production environment with Bitbucket (waited for token expiry, webhook succeeded after fix)
This commit is contained in:
@@ -32,6 +32,7 @@ import (
|
||||
"go.woodpecker-ci.org/woodpecker/v3/server/forge/common"
|
||||
forge_types "go.woodpecker-ci.org/woodpecker/v3/server/forge/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/server/store"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/shared/httputil"
|
||||
shared_utils "go.woodpecker-ci.org/woodpecker/v3/shared/utils"
|
||||
)
|
||||
@@ -423,6 +424,14 @@ func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *mod
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Refresh the OAuth token before making API calls.
|
||||
// The token may be expired, and without this refresh the API calls below
|
||||
// would fail with "OAuth2 access token expired" error.
|
||||
_store, ok := store.TryFromContext(ctx)
|
||||
if ok {
|
||||
forge.Refresh(ctx, c, _store, u)
|
||||
}
|
||||
|
||||
switch pl.Event {
|
||||
case model.EventPush:
|
||||
// List only the latest push changes
|
||||
|
||||
@@ -692,6 +692,11 @@ func (c *client) loadChangedFilesFromPullRequest(ctx context.Context, pull *gith
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Refresh the OAuth token before making API calls.
|
||||
// The token may be expired, and without this refresh the API calls below
|
||||
// would fail with an authentication error.
|
||||
forge.Refresh(ctx, c, _store, user)
|
||||
|
||||
gh := c.newClientToken(ctx, user.AccessToken)
|
||||
fileList := make([]string, 0, 16)
|
||||
|
||||
@@ -730,6 +735,11 @@ func (c *client) getTagCommitSHA(ctx context.Context, repo *model.Repo, tagName
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Refresh the OAuth token before making API calls.
|
||||
// The token may be expired, and without this refresh the API calls below
|
||||
// would fail with an authentication error.
|
||||
forge.Refresh(ctx, c, _store, user)
|
||||
|
||||
gh := c.newClientToken(ctx, user.AccessToken)
|
||||
|
||||
page := 1
|
||||
@@ -785,6 +795,11 @@ func (c *client) loadChangedFilesFromCommits(ctx context.Context, tmpRepo *model
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Refresh the OAuth token before making API calls.
|
||||
// The token may be expired, and without this refresh the API calls below
|
||||
// would fail with an authentication error.
|
||||
forge.Refresh(ctx, c, _store, user)
|
||||
|
||||
gh := c.newClientToken(ctx, user.AccessToken)
|
||||
fileList := make([]string, 0, 16)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user