package runtime
import (
"encoding/base64"
"fmt"
"net/http"
)
// Authenticator attaches credentials to an outgoing request.
//
// Return a non-nil error to abort the request before it leaves the client.
type Authenticator interface {
AuthenticateRequest(req *http.Request) error
}
// BearerAuth sends `Authorization: Bearer <Token>`.
//
// Use the Token field for a static token, or TokenProvider for a
// function that returns the current token (evaluated per-request).
// If both are set, TokenProvider takes precedence.
type BearerAuth struct {
Token string
TokenProvider func() string
}
func (b BearerAuth) AuthenticateRequest(req *http.Request) error {
token := b.Token
if b.TokenProvider != nil {
token = b.TokenProvider()
}
if token == "" {
return fmt.Errorf("bearer auth: empty token")
}
req.Header.Set("Authorization", "Bearer "+token)
return nil
}
// APIKeyLocation enumerates where an API key is placed on the wire.
type APIKeyLocation int
const (
APIKeyInHeader APIKeyLocation = iota
APIKeyInQuery
APIKeyInCookie
)
// APIKeyAuth attaches a named API key to a request.
type APIKeyAuth struct {
Key string
Name string
Location APIKeyLocation
}
func (a APIKeyAuth) AuthenticateRequest(req *http.Request) error {
if a.Key == "" || a.Name == "" {
return fmt.Errorf("api key auth: empty key or name")
}
switch a.Location {
case APIKeyInHeader:
req.Header.Set(a.Name, a.Key)
case APIKeyInQuery:
q := req.URL.Query()
q.Set(a.Name, a.Key)
req.URL.RawQuery = q.Encode()
case APIKeyInCookie:
req.AddCookie(&http.Cookie{Name: a.Name, Value: a.Key})
default:
return fmt.Errorf("api key auth: unknown location %d", a.Location)
}
return nil
}
// BasicAuth sends `Authorization: Basic <base64(user:pass)>`.
type BasicAuth struct {
Username string
Password string
}
func (b BasicAuth) AuthenticateRequest(req *http.Request) error {
creds := b.Username + ":" + b.Password
encoded := base64.StdEncoding.EncodeToString([]byte(creds))
req.Header.Set("Authorization", "Basic "+encoded)
return nil
}