diff --git a/lib/rest/rest.go b/lib/rest/rest.go index 20ee75cb8..a6a94070d 100644 --- a/lib/rest/rest.go +++ b/lib/rest/rest.go @@ -151,6 +151,7 @@ type Opts struct { NoRedirect bool // if this is set then the client won't follow redirects // On Redirects, call this function - see the http.Client docs: https://pkg.go.dev/net/http#Client CheckRedirect func(req *http.Request, via []*http.Request) error + AuthRedirect bool // if this is set then the client will redirect with Auth } // Copy creates a copy of the options @@ -216,6 +217,34 @@ func (api *Client) Do(req *http.Request) (*http.Response, error) { return api.c.Do(req) } +// ClientWithAuthRedirects makes a new http client which will re-apply Auth on redirects +func ClientWithAuthRedirects(c *http.Client) *http.Client { + clientCopy := *c + clientCopy.CheckRedirect = func(req *http.Request, via []*http.Request) error { + if len(via) >= 10 { + return errors.New("stopped after 10 redirects") + } else if len(via) == 0 { + return nil + } + prevReq := via[len(via)-1] + resp := req.Response + if resp == nil { + return nil + } + // Look at previous response to see if it was a redirect and preserve auth if so + switch resp.StatusCode { + case http.StatusMovedPermanently, http.StatusFound, http.StatusSeeOther, http.StatusTemporaryRedirect, http.StatusPermanentRedirect: + // Reapply Auth (if any) from previous request on redirect + auth := prevReq.Header.Get("Authorization") + if auth != "" { + req.Header.Add("Authorization", auth) + } + } + return nil + } + return &clientCopy +} + // Call makes the call and returns the http.Response // // if err == nil then resp.Body will need to be closed unless @@ -310,6 +339,8 @@ func (api *Client) Call(ctx context.Context, opts *Opts) (resp *http.Response, e clientCopy := *api.c clientCopy.CheckRedirect = opts.CheckRedirect c = &clientCopy + } else if opts.AuthRedirect { + c = ClientWithAuthRedirects(api.c) } else { c = api.c }