Documentation
¶
Index ¶
- Constants
- func NewAuthClient(mode, secret string, opts ...ClientOption) (*http.Client, error)
- func NewClient(opts ...ClientOption) (*http.Client, error)
- type AuthConfig
- type ClientOption
- func WithHMACHeaders(signature, timestamp, nonce string) ClientOption
- func WithHeaderName(name string) ClientOption
- func WithInsecureSkipVerify(skip bool) ClientOption
- func WithMTLSFromBytes(certPEM, keyPEM []byte) ClientOption
- func WithMTLSFromFile(certPath, keyPath string) ClientOption
- func WithMaxBodySize(maxBytes int64) ClientOption
- func WithMinTLSVersion(version uint16) ClientOption
- func WithRequestID(fn func() string) ClientOption
- func WithRequestIDHeader(name string) ClientOption
- func WithSkipAuthFunc(fn func(*http.Request) bool) ClientOption
- func WithTLSCertFromBytes(certPEM []byte) ClientOption
- func WithTLSCertFromFile(path string) ClientOption
- func WithTLSCertFromURL(ctx context.Context, url string) ClientOption
- func WithTimeout(timeout time.Duration) ClientOption
- func WithTransport(transport http.RoundTripper) ClientOption
- type SecureString
- type VerifyOption
- type VerifyOptions
Constants ¶
const ( AuthModeNone = "none" // No authentication AuthModeSimple = "simple" // Simple API secret in header AuthModeHMAC = "hmac" // HMAC-SHA256 signature AuthModeGitHub = "github" // GitHub webhook-style HMAC-SHA256 signature )
Authentication mode constants
const ( DefaultAPISecretHeader = "X-API-Secret" // Default header for simple mode DefaultSignatureHeader = "X-Signature" // Default signature header for HMAC mode DefaultTimestampHeader = "X-Timestamp" // Default timestamp header for HMAC mode DefaultNonceHeader = "X-Nonce" // Default nonce header for HMAC mode DefaultGitHubSignatureHeader = "X-Hub-Signature-256" // Default signature header for GitHub mode DefaultRequestIDHeader = "X-Request-ID" // Default request ID header for tracing )
Default header name constants
const ( DefaultVerifyMaxAge = 5 * time.Minute // Default maximum age for request timestamps DefaultVerifyMaxBodySize = 10 * 1024 * 1024 // Default maximum request body size (10MB) )
Default verification option constants
const ( DefaultClientTimeout = 30 * time.Second // Default HTTP client timeout DefaultCertFetchTimeout = 30 * time.Second // Default timeout for fetching certificates from URLs )
Default client option constants
Variables ¶
This section is empty.
Functions ¶
func NewAuthClient ¶
func NewAuthClient(mode, secret string, opts ...ClientOption) (*http.Client, error)
NewAuthClient creates an HTTP client with automatic authentication.
The client automatically adds authentication headers to all requests based on the specified mode (none, simple, or HMAC).
Parameters:
- mode: Authentication mode (AuthModeNone, AuthModeSimple, AuthModeHMAC)
- secret: Shared secret key for authentication
- opts: Optional configuration (timeout, custom headers, etc.)
Returns an error if any option fails (e.g., certificate file not found, invalid mTLS certificate pair, or failed to download certificate from URL).
Example (minimal):
client, err := httpclient.NewAuthClient(httpclient.AuthModeHMAC, "secret")
if err != nil {
log.Fatal(err)
}
resp, err := client.Get("https://api.example.com/data")
Example (with options):
client, err := httpclient.NewAuthClient(
httpclient.AuthModeHMAC,
"secret",
httpclient.WithTimeout(10*time.Second),
httpclient.WithMaxBodySize(5*1024*1024),
httpclient.WithSkipAuthFunc(func(req *http.Request) bool {
return strings.HasPrefix(req.URL.Path, "/health")
}),
)
if err != nil {
log.Fatal(err)
}
Example (with custom TLS certificate):
ctx := context.Background()
client, err := httpclient.NewAuthClient(
httpclient.AuthModeHMAC,
"secret",
httpclient.WithTLSCertFromFile("/etc/ssl/certs/company-ca.crt"),
httpclient.WithTLSCertFromURL(ctx, "https://ca.example.com/cert.pem"),
)
if err != nil {
log.Fatal(err)
}
Example (skip TLS verification for testing):
client, err := httpclient.NewAuthClient(
httpclient.AuthModeHMAC,
"secret",
httpclient.WithInsecureSkipVerify(true),
)
if err != nil {
log.Fatal(err)
}
Example (with mTLS):
client, err := httpclient.NewAuthClient(
httpclient.AuthModeHMAC,
"secret",
httpclient.WithMTLSFromFile("/path/to/client.crt", "/path/to/client.key"),
)
if err != nil {
log.Fatal(err)
}
Note: This implementation reads the entire request body into memory for signature calculation. For large file uploads (>10MB), consider using AddAuthHeaders directly with streaming.
func NewClient ¶ added in v0.10.0
func NewClient(opts ...ClientOption) (*http.Client, error)
NewClient creates a standard HTTP client without authentication.
This is a convenience wrapper around NewAuthClient with AuthModeNone. Use this when you need a plain HTTP client with optional custom configuration like timeout, TLS certificates, or request ID tracking, but don't need authentication.
Parameters:
- opts: Optional configuration (timeout, TLS certs, request ID, etc.)
Returns an error if any option fails (e.g., certificate file not found).
Example (basic):
client, err := httpclient.NewClient()
if err != nil {
log.Fatal(err)
}
resp, err := client.Get("https://api.example.com/public")
Example (with options):
client, err := httpclient.NewClient(
httpclient.WithTimeout(10*time.Second),
httpclient.WithMaxBodySize(5*1024*1024),
httpclient.WithTLSCertFromFile("/etc/ssl/certs/ca.crt"),
)
if err != nil {
log.Fatal(err)
}
Types ¶
type AuthConfig ¶
type AuthConfig struct {
Mode string // "none", "simple", "hmac" or "github"
Secret SecureString // Shared secret key (stored securely, redacted in logs)
HeaderName string // Custom header name for simple mode (default: "X-API-Secret")
SignatureHeader string // Signature header name for HMAC mode (default: "X-Signature")
TimestampHeader string // Timestamp header name for HMAC mode (default: "X-Timestamp")
NonceHeader string // Nonce header name for HMAC mode (default: "X-Nonce")
}
AuthConfig holds authentication configuration
func NewAuthConfig ¶
func NewAuthConfig(mode, secret string) *AuthConfig
NewAuthConfig creates a new AuthConfig with defaults
func (*AuthConfig) Verify ¶ added in v0.5.0
func (c *AuthConfig) Verify(req *http.Request, opts ...VerifyOption) error
Verify verifies the request based on the configured authentication mode. This is the unified verification method that automatically selects the appropriate verification logic based on AuthConfig.Mode.
For AuthModeNone: No verification is performed, returns nil immediately. For AuthModeSimple: Verifies the API secret header matches the configured secret. For AuthModeHMAC: Verifies HMAC signature with timestamp validation and body size checks.
Example:
// Create auth config
auth := NewAuthConfig(AuthModeSimple, "my-secret")
// Verify request in middleware
if err := auth.Verify(req); err != nil {
http.Error(w, "Authentication failed", http.StatusUnauthorized)
return
}
// For HMAC mode with custom options
auth := NewAuthConfig(AuthModeHMAC, "hmac-secret")
err := auth.Verify(req,
WithVerifyMaxAge(10*time.Minute),
WithVerifyMaxBodySize(5*1024*1024),
)
type ClientOption ¶
type ClientOption func(*clientOptions)
ClientOption is a function type for configuring the HTTP client.
func WithHMACHeaders ¶
func WithHMACHeaders(signature, timestamp, nonce string) ClientOption
WithHMACHeaders sets custom header names for HMAC authentication mode.
Default: signature="X-Signature", timestamp="X-Timestamp", nonce="X-Nonce"
Example:
client := NewAuthClient(AuthModeHMAC, "secret",
WithHMACHeaders("X-Sig", "X-Time", "X-ID"))
func WithHeaderName ¶
func WithHeaderName(name string) ClientOption
WithHeaderName sets a custom header name for simple authentication mode.
Default: "X-API-Secret"
Example:
client := NewAuthClient(AuthModeSimple, "key",
WithHeaderName("Authorization"))
func WithInsecureSkipVerify ¶ added in v0.5.0
func WithInsecureSkipVerify(skip bool) ClientOption
WithInsecureSkipVerify disables TLS certificate verification. This is useful for testing with self-signed certificates or development environments.
WARNING: This makes your application vulnerable to man-in-the-middle attacks. Never use this in production environments.
Example:
client := NewAuthClient(AuthModeHMAC, "secret",
WithInsecureSkipVerify(true))
func WithMTLSFromBytes ¶ added in v0.7.0
func WithMTLSFromBytes(certPEM, keyPEM []byte) ClientOption
WithMTLSFromBytes loads a client certificate and private key from byte content for mTLS (mutual TLS) authentication. The certificate and key must be in PEM format.
mTLS provides two-way authentication where both the client and server verify each other's identity using certificates.
Example:
certPEM := []byte(`-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----`)
keyPEM := []byte(`-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----`)
client, err := NewAuthClient(AuthModeHMAC, "secret",
WithMTLSFromBytes(certPEM, keyPEM))
if err != nil {
log.Fatal(err)
}
func WithMTLSFromFile ¶ added in v0.7.0
func WithMTLSFromFile(certPath, keyPath string) ClientOption
WithMTLSFromFile loads a client certificate and private key from files for mTLS (mutual TLS) authentication. The certificate and key must be in PEM format.
mTLS provides two-way authentication where both the client and server verify each other's identity using certificates.
Example:
client, err := NewAuthClient(AuthModeHMAC, "secret",
WithMTLSFromFile("/path/to/client.crt", "/path/to/client.key"))
if err != nil {
log.Fatal(err)
}
func WithMaxBodySize ¶
func WithMaxBodySize(maxBytes int64) ClientOption
WithMaxBodySize sets the maximum request body size in bytes. Requests with larger bodies will return an error. Set to 0 to disable the limit (not recommended).
Default: 10MB (10 * 1024 * 1024 bytes)
Example:
client := NewAuthClient(AuthModeHMAC, "secret",
WithMaxBodySize(5*1024*1024)) // 5MB limit
func WithMinTLSVersion ¶ added in v0.9.0
func WithMinTLSVersion(version uint16) ClientOption
WithMinTLSVersion sets the minimum TLS version for HTTPS connections. By default, TLS 1.2 is used for backwards compatibility with older servers.
Common values:
- tls.VersionTLS12 (0x0303) - TLS 1.2 (default, widely supported)
- tls.VersionTLS13 (0x0304) - TLS 1.3 (enhanced security, faster handshakes)
Note: TLS 1.3 provides stronger security with improved cipher suites, forward secrecy, and faster handshakes, but may not be supported by older servers. Use TLS 1.3 when you control both client and server, or when security requirements mandate it.
Example (enforce TLS 1.3):
client, err := httpclient.NewAuthClient(
httpclient.AuthModeHMAC,
"secret",
httpclient.WithMinTLSVersion(tls.VersionTLS13),
)
func WithRequestID ¶ added in v0.8.0
func WithRequestID(fn func() string) ClientOption
WithRequestID sets a function that generates unique request IDs for request tracing. The generated ID will be automatically added to each request in the X-Request-ID header (or custom header name set via WithRequestIDHeader).
This is useful for: - Correlating client-side and server-side logs - Distributed tracing across microservices - Debugging and troubleshooting request flows
Default: No request ID is added
Example with UUID:
import "github.com/google/uuid"
client := NewAuthClient(AuthModeHMAC, "secret",
WithRequestID(func() string {
return uuid.New().String()
}))
Example with custom format:
client := NewAuthClient(AuthModeHMAC, "secret",
WithRequestID(func() string {
return fmt.Sprintf("req-%d-%s", time.Now().Unix(), randomString(8))
}))
func WithRequestIDHeader ¶ added in v0.8.0
func WithRequestIDHeader(name string) ClientOption
WithRequestIDHeader sets a custom header name for the request ID. This is only used when WithRequestID is also configured.
Default: "X-Request-ID"
Example:
client := NewAuthClient(AuthModeHMAC, "secret",
WithRequestID(uuid.New().String),
WithRequestIDHeader("X-Correlation-ID"))
func WithSkipAuthFunc ¶
func WithSkipAuthFunc(fn func(*http.Request) bool) ClientOption
WithSkipAuthFunc sets a function that determines whether to skip authentication for a given request. This is useful for health checks or other public endpoints.
Example:
client := NewAuthClient(AuthModeHMAC, "secret",
WithSkipAuthFunc(func(req *http.Request) bool {
return strings.HasPrefix(req.URL.Path, "/health")
}))
func WithTLSCertFromBytes ¶ added in v0.4.0
func WithTLSCertFromBytes(certPEM []byte) ClientOption
WithTLSCertFromBytes adds a TLS certificate from byte content to the trusted certificate pool. This is useful for embedding certificates directly in the application or loading them from external sources.
The certificate must be in PEM format. Multiple certificates can be added by calling this function multiple times.
Example:
certPEM := []byte(`-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKL0UG+mRKm...
-----END CERTIFICATE-----`)
client := NewAuthClient(AuthModeHMAC, "secret",
WithTLSCertFromBytes(certPEM))
func WithTLSCertFromFile ¶ added in v0.4.0
func WithTLSCertFromFile(path string) ClientOption
WithTLSCertFromFile reads a TLS certificate from the specified file path and adds it to the trusted certificate pool. This is useful for enterprise environments with custom certificate authorities.
The certificate must be in PEM format. Multiple certificates can be added by calling this function multiple times.
Example:
client := NewAuthClient(AuthModeHMAC, "secret",
WithTLSCertFromFile("/etc/ssl/certs/company-ca.crt"))
func WithTLSCertFromURL ¶ added in v0.4.0
func WithTLSCertFromURL(ctx context.Context, url string) ClientOption
WithTLSCertFromURL downloads a TLS certificate from the specified URL and adds it to the trusted certificate pool. This is useful for enterprise environments with custom certificate authorities.
The certificate must be in PEM format. Multiple certificates can be added by calling this function multiple times.
Security: The download uses system certificate pool for TLS verification to prevent MITM attacks during certificate retrieval. The connection enforces TLS 1.2+ security.
Example:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client := NewAuthClient(AuthModeHMAC, "secret",
WithTLSCertFromURL(ctx, "https://internal-ca.company.com/ca.crt"))
func WithTimeout ¶
func WithTimeout(timeout time.Duration) ClientOption
WithTimeout sets the request timeout for the HTTP client.
Default: 30 seconds
Example:
client := NewAuthClient(AuthModeHMAC, "secret",
WithTimeout(10*time.Second))
func WithTransport ¶
func WithTransport(transport http.RoundTripper) ClientOption
WithTransport sets a custom underlying HTTP transport.
Default: http.DefaultTransport
IMPORTANT: If you use TLS options (WithTLSCert*, WithMTLS*, WithInsecureSkipVerify), you must provide an *http.Transport (not any other RoundTripper implementation). Non-Transport RoundTrippers cannot be combined with TLS options and will return an error.
If you need custom middleware (logging, metrics, tracing) with TLS options, configure TLS in your *http.Transport and wrap it with your middleware after creating the client:
// 1. Create Transport with TLS
transport := &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
},
}
// 2. Create authenticated client
authClient, _ := NewAuthClient(AuthModeHMAC, secret, WithTransport(transport))
// 3. Wrap with your middleware
authClient.Transport = &LoggingRoundTripper{
Next: authClient.Transport,
}
Example (basic):
customTransport := &http.Transport{
MaxIdleConns: 100,
}
client := NewAuthClient(AuthModeHMAC, "secret",
WithTransport(customTransport))
type SecureString ¶ added in v0.9.0
type SecureString struct {
// contains filtered or unexported fields
}
SecureString is a type that stores sensitive strings (secrets, API keys) and prevents accidental leakage through logging or debugging output. When printed using fmt.Printf, fmt.Println, or %v/%+v/%#v formatters, it displays "***REDACTED***" instead of the actual value.
func NewSecureString ¶ added in v0.9.0
func NewSecureString(s string) SecureString
NewSecureString creates a new SecureString from a string value
func (SecureString) Bytes ¶ added in v0.9.0
func (s SecureString) Bytes() []byte
Bytes returns the actual secret value as a byte slice for internal use
func (SecureString) GoString ¶ added in v0.9.0
func (s SecureString) GoString() string
GoString implements fmt.GoStringer interface for %#v formatting
func (SecureString) IsEmpty ¶ added in v0.9.0
func (s SecureString) IsEmpty() bool
IsEmpty returns true if the SecureString contains no data
func (SecureString) String ¶ added in v0.9.0
func (s SecureString) String() string
String implements fmt.Stringer interface to prevent accidental secret leakage
type VerifyOption ¶ added in v0.4.0
type VerifyOption func(*VerifyOptions)
VerifyOption is a function that configures VerifyOptions
func WithVerifyMaxAge ¶ added in v0.4.0
func WithVerifyMaxAge(d time.Duration) VerifyOption
WithVerifyMaxAge sets the maximum age for request timestamps during verification
func WithVerifyMaxBodySize ¶ added in v0.4.0
func WithVerifyMaxBodySize(size int64) VerifyOption
WithVerifyMaxBodySize sets the maximum request body size in bytes during verification
type VerifyOptions ¶ added in v0.4.0
type VerifyOptions struct {
MaxAge time.Duration // Maximum age of request timestamp (default: 5 minutes)
MaxBodySize int64 // Maximum request body size in bytes (default: 10MB)
}
VerifyOptions holds options for signature verification