feat: add AuthenticateBasic bool + NewRequestAuthenticator() with sane defaults

Co-authored-by: coolaj86 <122831+coolaj86@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-02 07:39:28 +00:00
parent 886888d6bb
commit 780ad06089
2 changed files with 22 additions and 2 deletions

View File

@ -14,7 +14,12 @@ var ErrNoCredentials = errors.New("no credentials provided")
// RequestAuthenticator extracts credentials from an HTTP request and delegates // RequestAuthenticator extracts credentials from an HTTP request and delegates
// verification to a BasicAuthenticator. It supports Basic Auth, Authorization // verification to a BasicAuthenticator. It supports Basic Auth, Authorization
// header tokens, custom token headers, and query-parameter tokens. // header tokens, custom token headers, and query-parameter tokens.
//
// Use NewRequestAuthenticator for sane defaults.
type RequestAuthenticator struct { type RequestAuthenticator struct {
// AuthenticateBasic enables HTTP Basic Auth (Authorization: Basic …).
AuthenticateBasic bool
// AuthorizationSchemes lists accepted schemes for "Authorization: <scheme> <token>". // AuthorizationSchemes lists accepted schemes for "Authorization: <scheme> <token>".
// nil or an empty slice skips the Authorization header entirely; // nil or an empty slice skips the Authorization header entirely;
// ["*"] accepts any scheme; ["Bearer", "Token"] restricts to those schemes. // ["*"] accepts any scheme; ["Bearer", "Token"] restricts to those schemes.
@ -29,6 +34,18 @@ type RequestAuthenticator struct {
TokenQueryParams []string TokenQueryParams []string
} }
// NewRequestAuthenticator returns a RequestAuthenticator with sane defaults:
// Basic Auth enabled, Bearer/Token Authorization schemes, common API-key
// headers, and access_token/token query params.
func NewRequestAuthenticator() *RequestAuthenticator {
return &RequestAuthenticator{
AuthenticateBasic: true,
AuthorizationSchemes: []string{"Bearer", "Token"},
TokenHeaders: []string{"X-API-Key", "X-Auth-Token", "X-Access-Token"},
TokenQueryParams: []string{"access_token", "token"},
}
}
// Authenticate extracts credentials from r in this order: // Authenticate extracts credentials from r in this order:
// 1. Basic Auth (Authorization: Basic …) // 1. Basic Auth (Authorization: Basic …)
// 2. Authorization: <scheme> <token> (filtered by AuthorizationSchemes) // 2. Authorization: <scheme> <token> (filtered by AuthorizationSchemes)
@ -38,9 +55,11 @@ type RequestAuthenticator struct {
// Returns ErrNoCredentials if no credential form is present in the request. // Returns ErrNoCredentials if no credential form is present in the request.
func (ra *RequestAuthenticator) Authenticate(r *http.Request, a BasicAuthenticator) (BasicPrinciple, error) { func (ra *RequestAuthenticator) Authenticate(r *http.Request, a BasicAuthenticator) (BasicPrinciple, error) {
// 1. Basic Auth // 1. Basic Auth
if ra.AuthenticateBasic {
if username, password, ok := r.BasicAuth(); ok { if username, password, ok := r.BasicAuth(); ok {
return a.Authenticate(username, password) return a.Authenticate(username, password)
} }
}
// 2. Authorization: <scheme> <token> // 2. Authorization: <scheme> <token>
// AuthorizationSchemes must be non-empty to check the Authorization header; // AuthorizationSchemes must be non-empty to check the Authorization header;

View File

@ -36,6 +36,7 @@ var pingWriter jsonl.Writer
var smsAuth *csvauth.Auth var smsAuth *csvauth.Auth
var smsRequestAuth = &auth.RequestAuthenticator{ var smsRequestAuth = &auth.RequestAuthenticator{
AuthenticateBasic: true,
AuthorizationSchemes: []string{"*"}, AuthorizationSchemes: []string{"*"},
TokenHeaders: []string{"API-Key", "X-API-Key"}, TokenHeaders: []string{"API-Key", "X-API-Key"},
} }