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.
//
// Use the Key field for a static key, or KeyProvider for a function
// that returns the current key (evaluated per-request). If both are
// set, KeyProvider takes precedence.
type APIKeyAuth struct {
Key string
KeyProvider func() string
Name string
Location APIKeyLocation
}
func (a APIKeyAuth) AuthenticateRequest(req *http.Request) error {
key := a.Key
if a.KeyProvider != nil {
key = a.KeyProvider()
}
if key == "" || a.Name == "" {
return fmt.Errorf("api key auth: empty key or name")
}
switch a.Location {
case APIKeyInHeader:
req.Header.Set(a.Name, key)
case APIKeyInQuery:
q := req.URL.Query()
q.Set(a.Name, key)
req.URL.RawQuery = q.Encode()
case APIKeyInCookie:
req.AddCookie(&http.Cookie{Name: a.Name, Value: key})
default:
return fmt.Errorf("api key auth: unknown location %d", a.Location)
}
return nil
}
// BasicAuth sends `Authorization: Basic <base64(user:pass)>`.
//
// Use the Username/Password fields for static credentials, or
// UsernameProvider/PasswordProvider for functions that return the
// current credentials (evaluated per-request). If a provider is set,
// it takes precedence over the corresponding static field.
type BasicAuth struct {
Username string
Password string
UsernameProvider func() string
PasswordProvider func() string
}
func (b BasicAuth) AuthenticateRequest(req *http.Request) error {
user := b.Username
if b.UsernameProvider != nil {
user = b.UsernameProvider()
}
pass := b.Password
if b.PasswordProvider != nil {
pass = b.PasswordProvider()
}
creds := user + ":" + pass
encoded := base64.StdEncoding.EncodeToString([]byte(creds))
req.Header.Set("Authorization", "Basic "+encoded)
return nil
}