From 5d22b395b8d16613ba0c89e91b5c54fe14197202 Mon Sep 17 00:00:00 2001 From: Drake Thomsen <120344051+ThomsenDrake@users.noreply.github.com> Date: Fri, 27 Mar 2026 10:00:31 -0400 Subject: [PATCH 1/4] rpcclient: make HTTP Basic Auth optional via DisableAuth Add a DisableAuth field to ConnConfig that, when set to true, skips setting the Authorization header on RPC requests. This enables connecting to third-party RPC providers (e.g. Alchemy, GetBlock) that authenticate via API key in the URL path and reject requests containing an Authorization header with 401 errors. Previously, getAuth() unconditionally set BasicAuth or attempted cookie auth, leaving no way to disable authentication entirely. Fixes #2505 --- rpcclient/infrastructure.go | 38 ++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/rpcclient/infrastructure.go b/rpcclient/infrastructure.go index 2d53fcfd..5d2d3b2c 100644 --- a/rpcclient/infrastructure.go +++ b/rpcclient/infrastructure.go @@ -811,11 +811,13 @@ retryloop: } // Configure basic access authorization. - user, pass, authErr := config.getAuth() - if authErr != nil { - return nil, authErr + if !config.DisableAuth { + user, pass, authErr := config.getAuth() + if authErr != nil { + return nil, authErr + } + httpReq.SetBasicAuth(user, pass) } - httpReq.SetBasicAuth(user, pass) httpResponse, err = httpClient.Do(httpReq) @@ -1330,6 +1332,12 @@ type ConnConfig struct { // EnableBCInfoHacks is an option provided to enable compatibility hacks // when connecting to blockchain.info RPC server EnableBCInfoHacks bool + + // DisableAuth instructs the client to skip setting the Authorization + // header on RPC requests. This is useful when connecting to third-party + // RPC providers that authenticate via API key in the URL path and + // reject requests containing an Authorization header with 401 errors. + DisableAuth bool } // getAuth returns the username and passphrase that will actually be used for @@ -1469,16 +1477,20 @@ func dial(config *ConnConfig) (*websocket.Conn, error) { dialer.NetDial = proxy.Dial } - // The RPC server requires basic authorization, so create a custom - // request header with the Authorization header set. - user, pass, err := config.getAuth() - if err != nil { - return nil, err - } - login := user + ":" + pass - auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login)) + // Configure basic access authorization. When DisableAuth is set, skip + // setting the Authorization header entirely. This is useful for + // third-party RPC providers that authenticate via API key in the URL + // path and reject requests containing an Authorization header. requestHeader := make(http.Header) - requestHeader.Add("Authorization", auth) + if !config.DisableAuth { + user, pass, err := config.getAuth() + if err != nil { + return nil, err + } + login := user + ":" + pass + auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(login)) + requestHeader.Add("Authorization", auth) + } for key, value := range config.ExtraHeaders { requestHeader.Add(key, value) } From 9b849c17385027e631ec95f87c57213bc54d85b5 Mon Sep 17 00:00:00 2001 From: Drake Thomsen <120344051+ThomsenDrake@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:18:48 -0400 Subject: [PATCH 2/4] rpcclient: add tests for DisableAuth header behavior Add table-driven tests that verify: - Authorization header is omitted when DisableAuth is true - Authorization header is present when DisableAuth is false - Default (zero value) behavior includes Authorization header Suggested by @TechLateef in #2514. --- rpcclient/disableauth_test.go | 109 ++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 rpcclient/disableauth_test.go diff --git a/rpcclient/disableauth_test.go b/rpcclient/disableauth_test.go new file mode 100644 index 00000000..4ef5c28e --- /dev/null +++ b/rpcclient/disableauth_test.go @@ -0,0 +1,109 @@ +package rpcclient + +import ( + "encoding/base64" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +// TestDisableAuth verifies that the DisableAuth field correctly controls +// whether the Authorization header is sent on RPC requests. +func TestDisableAuth(t *testing.T) { + t.Parallel() + + t.Run("DisableAuth true omits Authorization header", func(t *testing.T) { + t.Parallel() + + var gotAuth string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotAuth = r.Header.Get("Authorization") + // Return a valid JSON-RPC response so the client doesn't retry. + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"result":null,"error":null,"id":1}`)) + })) + defer srv.Close() + + addr := strings.TrimPrefix(srv.URL, "http://") + client, err := New(&ConnConfig{ + Host: addr, + HTTPPostMode: true, + DisableAuth: true, + DisableTLS: true, + }, nil) + require.NoError(t, err) + defer client.Shutdown() + + // The client is now connected; issue a simple request to trigger + // handleSendPostMessage. + _, err = client.RawRequest("getblockchaininfo", nil) + // We don't care if the RPC itself errors — we only care about + // the Authorization header. + _ = err + + require.Empty(t, gotAuth, "Authorization header should be empty when DisableAuth is true") + }) + + t.Run("DisableAuth false includes Authorization header", func(t *testing.T) { + t.Parallel() + + var gotAuth string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotAuth = r.Header.Get("Authorization") + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"result":null,"error":null,"id":1}`)) + })) + defer srv.Close() + + addr := strings.TrimPrefix(srv.URL, "http://") + client, err := New(&ConnConfig{ + Host: addr, + HTTPPostMode: true, + DisableAuth: false, + DisableTLS: true, + User: "testuser", + Pass: "testpass", + }, nil) + require.NoError(t, err) + defer client.Shutdown() + + _, err = client.RawRequest("getblockchaininfo", nil) + _ = err + + expected := "Basic " + base64.StdEncoding.EncodeToString([]byte("testuser:testpass")) + require.Equal(t, expected, gotAuth, "Authorization header should be set when DisableAuth is false") + }) + + t.Run("DisableAuth default (zero value) includes Authorization header", func(t *testing.T) { + t.Parallel() + + var gotAuth string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotAuth = r.Header.Get("Authorization") + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"result":null,"error":null,"id":1}`)) + })) + defer srv.Close() + + addr := strings.TrimPrefix(srv.URL, "http://") + client, err := New(&ConnConfig{ + Host: addr, + HTTPPostMode: true, + // DisableAuth left as default (false) + DisableTLS: true, + User: "myuser", + Pass: "mypass", + }, nil) + require.NoError(t, err) + defer client.Shutdown() + + _, err = client.RawRequest("getblockchaininfo", nil) + _ = err + + expected := "Basic " + base64.StdEncoding.EncodeToString([]byte("myuser:mypass")) + require.Equal(t, expected, gotAuth, "Authorization header should be set by default (DisableAuth is false)") + }) +} From fe84a0e16bbfeca8393060fd7da5b3f73b79a15f Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Tue, 21 Jul 2026 17:26:20 -0700 Subject: [PATCH 3/4] rpcclient: wrap DisableAuth tests to 80 columns In this commit, we wrap the new DisableAuth regression tests to the btcd 80-column formatting convention. We also split the nested handler setup and assertions into logical stanzas so the tests match the surrounding style. --- rpcclient/disableauth_test.go | 127 +++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 48 deletions(-) diff --git a/rpcclient/disableauth_test.go b/rpcclient/disableauth_test.go index 4ef5c28e..e35a8887 100644 --- a/rpcclient/disableauth_test.go +++ b/rpcclient/disableauth_test.go @@ -19,20 +19,27 @@ func TestDisableAuth(t *testing.T) { t.Parallel() var gotAuth string - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - gotAuth = r.Header.Get("Authorization") - // Return a valid JSON-RPC response so the client doesn't retry. - w.Header().Set("Content-Type", "application/json") - w.Write([]byte(`{"result":null,"error":null,"id":1}`)) - })) + handler := http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + gotAuth = r.Header.Get("Authorization") + + // Return a valid JSON-RPC response so the client + // doesn't retry. + w.Header().Set("Content-Type", "application/json") + w.Write([]byte( + `{"result":null,"error":null,"id":1}`, + )) + }, + ) + srv := httptest.NewServer(handler) defer srv.Close() addr := strings.TrimPrefix(srv.URL, "http://") client, err := New(&ConnConfig{ - Host: addr, + Host: addr, HTTPPostMode: true, - DisableAuth: true, - DisableTLS: true, + DisableAuth: true, + DisableTLS: true, }, nil) require.NoError(t, err) defer client.Shutdown() @@ -40,32 +47,40 @@ func TestDisableAuth(t *testing.T) { // The client is now connected; issue a simple request to trigger // handleSendPostMessage. _, err = client.RawRequest("getblockchaininfo", nil) - // We don't care if the RPC itself errors — we only care about + // We don't care if the RPC itself errors. We only care about // the Authorization header. _ = err - require.Empty(t, gotAuth, "Authorization header should be empty when DisableAuth is true") + require.Empty( + t, gotAuth, + "Authorization header should be empty when DisableAuth is true", + ) }) t.Run("DisableAuth false includes Authorization header", func(t *testing.T) { t.Parallel() var gotAuth string - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - gotAuth = r.Header.Get("Authorization") - w.Header().Set("Content-Type", "application/json") - w.Write([]byte(`{"result":null,"error":null,"id":1}`)) - })) + handler := http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + gotAuth = r.Header.Get("Authorization") + w.Header().Set("Content-Type", "application/json") + w.Write([]byte( + `{"result":null,"error":null,"id":1}`, + )) + }, + ) + srv := httptest.NewServer(handler) defer srv.Close() addr := strings.TrimPrefix(srv.URL, "http://") client, err := New(&ConnConfig{ - Host: addr, + Host: addr, HTTPPostMode: true, - DisableAuth: false, - DisableTLS: true, - User: "testuser", - Pass: "testpass", + DisableAuth: false, + DisableTLS: true, + User: "testuser", + Pass: "testpass", }, nil) require.NoError(t, err) defer client.Shutdown() @@ -73,37 +88,53 @@ func TestDisableAuth(t *testing.T) { _, err = client.RawRequest("getblockchaininfo", nil) _ = err - expected := "Basic " + base64.StdEncoding.EncodeToString([]byte("testuser:testpass")) - require.Equal(t, expected, gotAuth, "Authorization header should be set when DisableAuth is false") + login := []byte("testuser:testpass") + expected := "Basic " + base64.StdEncoding.EncodeToString(login) + require.Equal( + t, expected, gotAuth, + "Authorization header should be set when DisableAuth is false", + ) }) - t.Run("DisableAuth default (zero value) includes Authorization header", func(t *testing.T) { - t.Parallel() + t.Run( + "DisableAuth default (zero value) includes Authorization header", + func(t *testing.T) { + t.Parallel() - var gotAuth string - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - gotAuth = r.Header.Get("Authorization") - w.Header().Set("Content-Type", "application/json") - w.Write([]byte(`{"result":null,"error":null,"id":1}`)) - })) - defer srv.Close() + var gotAuth string + handler := http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + gotAuth = r.Header.Get("Authorization") + w.Header().Set("Content-Type", "application/json") + w.Write([]byte( + `{"result":null,"error":null,"id":1}`, + )) + }, + ) + srv := httptest.NewServer(handler) + defer srv.Close() - addr := strings.TrimPrefix(srv.URL, "http://") - client, err := New(&ConnConfig{ - Host: addr, - HTTPPostMode: true, - // DisableAuth left as default (false) - DisableTLS: true, - User: "myuser", - Pass: "mypass", - }, nil) - require.NoError(t, err) - defer client.Shutdown() + addr := strings.TrimPrefix(srv.URL, "http://") + client, err := New(&ConnConfig{ + Host: addr, + HTTPPostMode: true, + DisableTLS: true, + User: "myuser", + Pass: "mypass", + }, nil) + require.NoError(t, err) + defer client.Shutdown() - _, err = client.RawRequest("getblockchaininfo", nil) - _ = err + _, err = client.RawRequest("getblockchaininfo", nil) + _ = err - expected := "Basic " + base64.StdEncoding.EncodeToString([]byte("myuser:mypass")) - require.Equal(t, expected, gotAuth, "Authorization header should be set by default (DisableAuth is false)") - }) + login := []byte("myuser:mypass") + expected := "Basic " + + base64.StdEncoding.EncodeToString(login) + require.Equal( + t, expected, gotAuth, + "Authorization header should be set by default", + ) + }, + ) } From 52d2fade69a915272c4188c9e7383c74cf919c3f Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Tue, 21 Jul 2026 17:38:21 -0700 Subject: [PATCH 4/4] rpcclient: harden DisableAuth transport tests In this commit, we make the DisableAuth tests observe successful requests instead of inferring them from an empty header. This closes a false-positive path where credential lookup could fail before the request reached the server. We also cover the WebSocket handshake, cookie bypass, and caller-provided headers across enabled and disabled auth. The public comment now makes clear that DisableAuth only suppresses rpcclient-generated Basic auth. --- rpcclient/disableauth_test.go | 282 +++++++++++++++++++++------------- rpcclient/infrastructure.go | 15 +- 2 files changed, 178 insertions(+), 119 deletions(-) diff --git a/rpcclient/disableauth_test.go b/rpcclient/disableauth_test.go index e35a8887..7bba3a5c 100644 --- a/rpcclient/disableauth_test.go +++ b/rpcclient/disableauth_test.go @@ -1,140 +1,202 @@ package rpcclient import ( + "context" "encoding/base64" + "io" "net/http" "net/http/httptest" + "path/filepath" "strings" "testing" + "time" + "github.com/gorilla/websocket" "github.com/stretchr/testify/require" ) -// TestDisableAuth verifies that the DisableAuth field correctly controls -// whether the Authorization header is sent on RPC requests. -func TestDisableAuth(t *testing.T) { - t.Parallel() +const ( + testRPCUser = "testuser" + testRPCPass = "testpass" + testCallerAuth = "Bearer test-api-key" + testExtraHeader = "X-Test-API-Key" + testExtraValue = "test-api-key" +) - t.Run("DisableAuth true omits Authorization header", func(t *testing.T) { - t.Parallel() +// disableAuthTestCase describes one authentication header configuration that +// must behave the same for HTTP POST and WebSocket transports. +type disableAuthTestCase struct { + name string + configure func(*ConnConfig) + wantAuthorization string +} - var gotAuth string - handler := http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - gotAuth = r.Header.Get("Authorization") +// disableAuthTestCases returns the shared transport authentication cases. +func disableAuthTestCases(missingCookie string) []disableAuthTestCase { + basicAuth := "Basic " + base64.StdEncoding.EncodeToString( + []byte(testRPCUser+":"+testRPCPass), + ) - // Return a valid JSON-RPC response so the client - // doesn't retry. - w.Header().Set("Content-Type", "application/json") - w.Write([]byte( - `{"result":null,"error":null,"id":1}`, - )) + return []disableAuthTestCase{ + { + name: "disabled omits generated authorization", + configure: func(config *ConnConfig) { + config.User = "" + config.Pass = "" + config.CookiePath = missingCookie + config.DisableAuth = true }, - ) - srv := httptest.NewServer(handler) - defer srv.Close() - - addr := strings.TrimPrefix(srv.URL, "http://") - client, err := New(&ConnConfig{ - Host: addr, - HTTPPostMode: true, - DisableAuth: true, - DisableTLS: true, - }, nil) - require.NoError(t, err) - defer client.Shutdown() - - // The client is now connected; issue a simple request to trigger - // handleSendPostMessage. - _, err = client.RawRequest("getblockchaininfo", nil) - // We don't care if the RPC itself errors. We only care about - // the Authorization header. - _ = err - - require.Empty( - t, gotAuth, - "Authorization header should be empty when DisableAuth is true", - ) - }) - - t.Run("DisableAuth false includes Authorization header", func(t *testing.T) { - t.Parallel() - - var gotAuth string - handler := http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - gotAuth = r.Header.Get("Authorization") - w.Header().Set("Content-Type", "application/json") - w.Write([]byte( - `{"result":null,"error":null,"id":1}`, - )) + }, + { + name: "disabled preserves caller authorization", + configure: func(config *ConnConfig) { + config.User = "" + config.Pass = "" + config.CookiePath = missingCookie + config.DisableAuth = true + config.ExtraHeaders["Authorization"] = + testCallerAuth }, - ) - srv := httptest.NewServer(handler) - defer srv.Close() + wantAuthorization: testCallerAuth, + }, + { + name: "explicit false includes basic authorization", + configure: func(config *ConnConfig) { + config.DisableAuth = false + }, + wantAuthorization: basicAuth, + }, + { + name: "zero value includes basic authorization", + configure: func(*ConnConfig) { + // Leave DisableAuth at its zero value. + }, + wantAuthorization: basicAuth, + }, + } +} - addr := strings.TrimPrefix(srv.URL, "http://") - client, err := New(&ConnConfig{ - Host: addr, - HTTPPostMode: true, - DisableAuth: false, - DisableTLS: true, - User: "testuser", - Pass: "testpass", - }, nil) - require.NoError(t, err) - defer client.Shutdown() +// newDisableAuthConfig creates the common configuration for the transport +// authentication cases. +func newDisableAuthConfig() *ConnConfig { + return &ConnConfig{ + User: testRPCUser, + Pass: testRPCPass, + ExtraHeaders: map[string]string{ + testExtraHeader: testExtraValue, + }, + } +} - _, err = client.RawRequest("getblockchaininfo", nil) - _ = err +// assertAuthHeaders verifies both generated or caller-supplied authorization +// and the independent extra header. +func assertAuthHeaders(t *testing.T, header http.Header, + wantAuthorization string) { - login := []byte("testuser:testpass") - expected := "Basic " + base64.StdEncoding.EncodeToString(login) - require.Equal( - t, expected, gotAuth, - "Authorization header should be set when DisableAuth is false", - ) - }) + t.Helper() - t.Run( - "DisableAuth default (zero value) includes Authorization header", - func(t *testing.T) { - t.Parallel() + require.Equal(t, wantAuthorization, header.Get("Authorization")) + require.Equal(t, testExtraValue, header.Get(testExtraHeader)) +} - var gotAuth string - handler := http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - gotAuth = r.Header.Get("Authorization") - w.Header().Set("Content-Type", "application/json") - w.Write([]byte( - `{"result":null,"error":null,"id":1}`, - )) +// TestDisableAuthHTTPPost verifies that DisableAuth controls generated Basic +// Auth headers on HTTP POST requests without suppressing caller headers. +func TestDisableAuthHTTPPost(t *testing.T) { + missingCookie := filepath.Join(t.TempDir(), "missing-cookie") + + for _, tc := range disableAuthTestCases(missingCookie) { + t.Run(tc.name, func(t *testing.T) { + requestHeader := make(chan http.Header, 1) + client := newPostModeTestClient(postRoundTripFunc( + func(req *http.Request) (*http.Response, error) { + requestHeader <- req.Header.Clone() + + return &http.Response{ + StatusCode: http.StatusOK, + Header: make(http.Header), + Body: io.NopCloser(strings.NewReader( + `{"result":1,"error":null,"id":1}`, + )), + }, nil }, - ) - srv := httptest.NewServer(handler) - defer srv.Close() + )) + client.config = newDisableAuthConfig() + client.config.Host = "127.0.0.1:8332" + client.config.DisableTLS = true + client.config.HTTPPostMode = true + tc.configure(client.config) - addr := strings.TrimPrefix(srv.URL, "http://") - client, err := New(&ConnConfig{ - Host: addr, - HTTPPostMode: true, - DisableTLS: true, - User: "myuser", - Pass: "mypass", - }, nil) + result, err := sendPostRequestWithRetry( + context.Background(), newPostTestRequest(), 1, + client.httpClient, client.config, client.httpURL, + false, + ) require.NoError(t, err) - defer client.Shutdown() + require.Equal(t, []byte("1"), result) - _, err = client.RawRequest("getblockchaininfo", nil) - _ = err + select { + case header := <-requestHeader: + assertAuthHeaders(t, header, tc.wantAuthorization) - login := []byte("myuser:mypass") - expected := "Basic " + - base64.StdEncoding.EncodeToString(login) - require.Equal( - t, expected, gotAuth, - "Authorization header should be set by default", - ) + case <-time.After(time.Second): + t.Fatal("timed out waiting for HTTP POST request") + } + }) + } +} + +// newWebsocketAuthServer creates a server that records the WebSocket handshake +// headers before upgrading the connection. +func newWebsocketAuthServer(t *testing.T) (string, <-chan http.Header) { + t.Helper() + + requestHeader := make(chan http.Header, 1) + upgrader := websocket.Upgrader{} + handler := http.HandlerFunc( + func(w http.ResponseWriter, req *http.Request) { + requestHeader <- req.Header.Clone() + + conn, err := upgrader.Upgrade(w, req, nil) + if err != nil { + return + } + defer func() { + _ = conn.Close() + }() }, ) + server := httptest.NewServer(handler) + t.Cleanup(server.Close) + + return strings.TrimPrefix(server.URL, "http://"), requestHeader +} + +// TestDisableAuthWebsocket verifies that DisableAuth controls generated Basic +// Auth headers on WebSocket handshakes without suppressing caller headers. +func TestDisableAuthWebsocket(t *testing.T) { + missingCookie := filepath.Join(t.TempDir(), "missing-cookie") + + for _, tc := range disableAuthTestCases(missingCookie) { + t.Run(tc.name, func(t *testing.T) { + host, requestHeader := newWebsocketAuthServer(t) + config := newDisableAuthConfig() + config.Host = host + config.DisableTLS = true + tc.configure(config) + + conn, err := dial(config) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, conn.Close()) + }) + + select { + case header := <-requestHeader: + assertAuthHeaders(t, header, tc.wantAuthorization) + + case <-time.After(time.Second): + t.Fatal("timed out waiting for WebSocket handshake") + } + }) + } } diff --git a/rpcclient/infrastructure.go b/rpcclient/infrastructure.go index 5d2d3b2c..a4548498 100644 --- a/rpcclient/infrastructure.go +++ b/rpcclient/infrastructure.go @@ -810,7 +810,7 @@ retryloop: httpReq.Header.Set(key, value) } - // Configure basic access authorization. + // Configure generated basic access authorization. if !config.DisableAuth { user, pass, authErr := config.getAuth() if authErr != nil { @@ -1333,10 +1333,9 @@ type ConnConfig struct { // when connecting to blockchain.info RPC server EnableBCInfoHacks bool - // DisableAuth instructs the client to skip setting the Authorization - // header on RPC requests. This is useful when connecting to third-party - // RPC providers that authenticate via API key in the URL path and - // reject requests containing an Authorization header with 401 errors. + // DisableAuth instructs the client to skip generating a Basic + // Authorization header for RPC requests. Caller-provided Authorization + // values in ExtraHeaders are still sent. DisableAuth bool } @@ -1477,10 +1476,8 @@ func dial(config *ConnConfig) (*websocket.Conn, error) { dialer.NetDial = proxy.Dial } - // Configure basic access authorization. When DisableAuth is set, skip - // setting the Authorization header entirely. This is useful for - // third-party RPC providers that authenticate via API key in the URL - // path and reject requests containing an Authorization header. + // Configure generated basic access authorization. Caller-provided + // headers are added independently below. requestHeader := make(http.Header) if !config.DisableAuth { user, pass, err := config.getAuth()