From 9b79800b07654c3f2fb7ef8bb5c494f4892715ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 08:10:17 +0000 Subject: [PATCH] refactor: remove Challenge() method; use w.Header().Set("WWW-Authenticate", ...) directly Co-authored-by: coolaj86 <122831+coolaj86@users.noreply.github.com> --- auth/request.go | 22 ++++++++++------------ auth/request_example_test.go | 8 +++++--- cmd/auth-proxy/main.go | 4 +++- cmd/smsapid/main.go | 8 ++++++-- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/auth/request.go b/auth/request.go index 8036c93..a40f7df 100644 --- a/auth/request.go +++ b/auth/request.go @@ -37,15 +37,22 @@ type RequestAuthenticator struct { // e.g. []string{"access_token", "token"}. TokenQueryParams []string - // WWWAuthenticate is the value sent in the WWW-Authenticate response header - // when Challenge is called. An empty string disables the header. + // WWWAuthenticate is the suggested value for the WWW-Authenticate response + // header. Set it on the response before writing a 401 Unauthorized so that + // clients know which auth scheme to use. An empty string means no header. // NewRequestAuthenticator sets this to "Basic". + // + // Example: + // + // if ra.WWWAuthenticate != "" { + // w.Header().Set("WWW-Authenticate", ra.WWWAuthenticate) + // } WWWAuthenticate string } // NewRequestAuthenticator returns a RequestAuthenticator with sane defaults: // Basic Auth enabled, Bearer/Token Authorization schemes, common API-key -// headers, access_token/token query params, and WWW-Authenticate: Basic. +// headers, access_token/token query params, and WWWAuthenticate "Basic". func NewRequestAuthenticator() *RequestAuthenticator { return &RequestAuthenticator{ AuthenticateBasic: true, @@ -56,15 +63,6 @@ func NewRequestAuthenticator() *RequestAuthenticator { } } -// Challenge sets the WWW-Authenticate response header to ra.WWWAuthenticate -// when it is non-empty. Call this before writing a 401 Unauthorized response -// so that clients know which auth scheme to use. -func (ra *RequestAuthenticator) Challenge(w http.ResponseWriter) { - if ra.WWWAuthenticate != "" { - w.Header().Set("WWW-Authenticate", ra.WWWAuthenticate) - } -} - // Authenticate extracts credentials from r in this order: // 1. Basic Auth (Authorization: Basic …) // 2. Authorization: (filtered by AuthorizationSchemes) diff --git a/auth/request_example_test.go b/auth/request_example_test.go index 626fc08..4eaf6c5 100644 --- a/auth/request_example_test.go +++ b/auth/request_example_test.go @@ -17,8 +17,8 @@ func (exampleCreds) Authenticate(username, password string) (auth.BasicPrinciple // ExampleRequestAuthenticator shows the typical usage pattern. // Build a RequestAuthenticator once (at startup), attach your credential // store as the Authenticator, then call Authenticate in each handler. -// Call Challenge before writing a 401 so the browser knows which scheme -// to offer. +// Set the WWW-Authenticate header before writing a 401 so the browser +// knows which scheme to offer. func ExampleRequestAuthenticator() { ra := auth.NewRequestAuthenticator() ra.Authenticator = exampleCreds{} // swap in your real credential store @@ -26,7 +26,9 @@ func ExampleRequestAuthenticator() { http.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) { principle, err := ra.Authenticate(r) if err != nil { - ra.Challenge(w) // sets WWW-Authenticate: Basic + if ra.WWWAuthenticate != "" { + w.Header().Set("WWW-Authenticate", ra.WWWAuthenticate) + } http.Error(w, "Unauthorized", http.StatusUnauthorized) return } diff --git a/cmd/auth-proxy/main.go b/cmd/auth-proxy/main.go index 20b96ce..e52caef 100644 --- a/cmd/auth-proxy/main.go +++ b/cmd/auth-proxy/main.go @@ -402,7 +402,9 @@ func (cli *MainConfig) newAuthProxyHandler(targetURL string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !cli.authorize(r) { - cli.ra.Challenge(w) + if cli.ra.WWWAuthenticate != "" { + w.Header().Set("WWW-Authenticate", cli.ra.WWWAuthenticate) + } http.Error(w, "Unauthorized", http.StatusUnauthorized) return } diff --git a/cmd/smsapid/main.go b/cmd/smsapid/main.go index 7f7d3d6..d837295 100644 --- a/cmd/smsapid/main.go +++ b/cmd/smsapid/main.go @@ -146,13 +146,17 @@ func requireSMSPermission(permission string) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if smsAuth == nil { - smsRequestAuth.Challenge(w) + if smsRequestAuth.WWWAuthenticate != "" { + w.Header().Set("WWW-Authenticate", smsRequestAuth.WWWAuthenticate) + } http.Error(w, "Unauthorized", http.StatusUnauthorized) return } cred, err := smsRequestAuth.Authenticate(r) if err != nil || !hasSMSPermission(cred.Permissions(), permission) { - smsRequestAuth.Challenge(w) + if smsRequestAuth.WWWAuthenticate != "" { + w.Header().Set("WWW-Authenticate", smsRequestAuth.WWWAuthenticate) + } http.Error(w, "Unauthorized", http.StatusUnauthorized) return }