httpclient

package module
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 16, 2026 License: MIT Imports: 17 Imported by: 1

README

go-httpclient

Trivy Security Scan Testing CodeQL codecov Go Report Card Go Reference

A lightweight, flexible Go package for adding configurable authentication to HTTP requests. Supports multiple authentication strategies including HMAC-SHA256 signatures with built-in protection against replay attacks and query parameter tampering.

Table of Contents

Why

Why do you need HTTP request authentication?

In modern distributed systems and microservices architectures, securing HTTP communication between services is critical:

  • Prevent Unauthorized Access: Ensure only authenticated clients can access your APIs
  • Protect Against Replay Attacks: Time-based signatures prevent attackers from reusing captured requests
  • Maintain Request Integrity: Cryptographic signatures detect any tampering with request data
  • Secure Query Parameters: Include URL parameters in signatures to prevent manipulation
  • Flexible Security Levels: Choose the right authentication strategy for your use case

Without proper authentication, your APIs are vulnerable to:

  • Unauthorized access and data breaches
  • Man-in-the-middle attacks
  • Request tampering and parameter injection
  • Replay attacks using captured requests

What

go-httpclient is a Go package that provides configurable HTTP authentication mechanisms for both client-side request signing and server-side request verification.

Four Authentication Modes
  1. None Mode (AuthModeNone)

    • No authentication headers added
    • Use for public endpoints or when authentication is handled elsewhere
  2. Simple Mode (AuthModeSimple)

    • API secret key sent in a custom header
    • Lightweight authentication for internal services
    • Default header: X-API-Secret (customizable)
  3. HMAC Mode (AuthModeHMAC)

    • HMAC-SHA256 cryptographic signatures
    • Three headers: signature, timestamp, and nonce
    • Includes request method, path, query parameters, and body in signature
    • Built-in replay attack prevention with timestamp validation
    • Default headers: X-Signature, X-Timestamp, X-Nonce (all customizable)
  4. GitHub Mode (AuthModeGitHub)

    • GitHub webhook-compatible HMAC-SHA256 signatures
    • Single header with "sha256=" prefix format
    • Signature includes only request body (compatible with GitHub webhooks)
    • Default header: X-Hub-Signature-256 (customizable)
    • No timestamp validation (use HTTPS and regular secret rotation)
Key Benefits
  • Automatic Authentication: One-line client creation with built-in request signing via NewAuthClient
  • Flexible Configuration: Option Pattern for easy customization without breaking changes
    • Client options: WithTimeout, WithMaxBodySize, WithSkipAuthFunc, WithHMACHeaders, etc.
    • Verification options: WithVerifyMaxAge, WithVerifyMaxBodySize
  • Custom TLS Certificates: Load certificates from files, URLs, or embedded content for enterprise PKI
  • DoS Protection: Configurable body size limits prevent memory exhaustion attacks (default: 10MB)
  • Zero Dependencies (except google/uuid for nonce generation)
  • Simple API: Easy to integrate into existing HTTP clients
  • Dual Purpose: Works for both client-side signing and server-side verification
  • Customizable: Override default header names to match your API standards
  • Production Ready: 90%+ test coverage, comprehensive linting, and security scanning
  • Well Tested: 1200+ lines of test code covering all scenarios

How

Installation
go get github.com/appleboy/go-httpclient
Quick Start

Option 1: Simple HTTP Client (No Authentication)

package main

import (
    "fmt"
    "log"

    "github.com/appleboy/go-httpclient"
)

func main() {
    // Create a simple HTTP client
    client, err := httpclient.NewClient()
    if err != nil {
        log.Fatal(err)
    }

    // Make requests - just like http.Client!
    resp, err := client.Get("https://api.example.com/public")
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    fmt.Println("Request sent successfully")
}

Option 2: Authenticated HTTP Client

package main

import (
    "bytes"
    "fmt"
    "log"

    "github.com/appleboy/go-httpclient"
)

func main() {
    // Create authenticated HTTP client
    client, err := httpclient.NewAuthClient(httpclient.AuthModeHMAC, "your-secret-key")
    if err != nil {
        log.Fatal(err)
    }

    // Send request - authentication headers added automatically!
    body := []byte(`{"user": "john"}`)
    resp, err := client.Post(
        "https://api.example.com/users",
        "application/json",
        bytes.NewReader(body),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    fmt.Println("Request sent with automatic HMAC authentication")
}
Usage Examples

For complete, runnable examples, see the _example directory. Each example includes detailed documentation and can be run independently.

No Authentication

For public endpoints or when authentication is not required, use the convenient NewClient() function:

// Recommended: Use NewClient() for clarity
client, err := httpclient.NewClient()
if err != nil {
    log.Fatal(err)
}
resp, err := client.Get("https://api.example.com/public")
// No authentication headers added

// With custom configuration
client, err := httpclient.NewClient(
    httpclient.WithTimeout(10*time.Second),
    httpclient.WithTLSCertFromFile("/etc/ssl/certs/ca.crt"),
)

// Alternative: Use NewAuthClient with AuthModeNone
client, err := httpclient.NewAuthClient(httpclient.AuthModeNone, "")
Simple API Key Authentication

For basic authentication with a shared secret:

// Create client with simple authentication (default header: X-API-Secret)
client := httpclient.NewAuthClient(httpclient.AuthModeSimple, "my-secret-key")

// Make requests - authentication is automatic
resp, err := client.Get("https://api.example.com/data")

// Request will automatically include:
// X-API-Secret: my-secret-key

See full example: _example/01-simple-auth

HMAC Signature Authentication

For cryptographically secure request signing:

// Create client with HMAC authentication
client := httpclient.NewAuthClient(httpclient.AuthModeHMAC, "shared-secret")

// Make requests - authentication is automatic
body := []byte(`{"action": "transfer", "amount": 100}`)
resp, err := client.Post(
    "https://api.example.com/transactions?user=123",
    "application/json",
    bytes.NewReader(body),
)

// Request will automatically include:
// X-Signature: a3c8f9b2... (HMAC-SHA256 signature)
// X-Timestamp: 1704067200 (Unix timestamp)
// X-Nonce: 550e8400-e29b-41d4-a716-446655440000 (UUID v4)

The signature is calculated as:

HMAC-SHA256(secret, timestamp + method + path + query + body)

For example:

message = "1704067200POST/transactions?user=123{\"action\":\"transfer\",\"amount\":100}"
signature = HMAC-SHA256("shared-secret", message)

See full example: _example/02-hmac-auth

GitHub Webhook-Style Authentication

GitHub mode provides compatibility with GitHub webhook signature format and other webhook providers using similar HMAC-SHA256 patterns:

// Create client with GitHub-style authentication
client := httpclient.NewAuthClient(httpclient.AuthModeGitHub, "webhook-secret")

// Make requests - authentication is automatic
payload := []byte(`{"action":"opened","pull_request":{"id":123}}`)
resp, err := client.Post(
    "https://api.example.com/webhook",
    "application/json",
    bytes.NewReader(payload),
)

// Request will automatically include:
// X-Hub-Signature-256: sha256=a3c8f9b2... (GitHub-style signature)

Server-side verification:

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    // Create auth config with GitHub mode
    auth := httpclient.NewAuthConfig(httpclient.AuthModeGitHub, "webhook-secret")

    // Verify signature
    if err := auth.Verify(r); err != nil {
        http.Error(w, "Invalid signature", http.StatusUnauthorized)
        return
    }

    // Body is preserved after verification
    body, _ := io.ReadAll(r.Body)
    var payload map[string]interface{}
    json.Unmarshal(body, &payload)

    log.Printf("Received webhook: %v", payload)
    w.WriteHeader(http.StatusOK)
}

Key differences from HMAC mode:

Feature HMAC Mode GitHub Mode
Signature content timestamp + method + path + query + body body only
Signature format hex digest (64 chars) "sha256=" + hex digest (71 chars)
Headers 3 (X-Signature, X-Timestamp, X-Nonce) 1 (X-Hub-Signature-256)
Timestamp validation ✅ Yes (±5 minutes) ❌ No
Replay attack protection ✅ Yes ⚠️ Limited (HTTPS + secret rotation recommended)

Security notes:

  • GitHub mode does NOT validate timestamps (GitHub webhooks don't provide them)
  • Always use HTTPS to protect the secret in transit
  • Regularly rotate webhook secrets to mitigate replay attack risks
  • Default body size limit (10MB) protects against DoS attacks
Custom Header Names

Override default header names to match your API standards:

// Simple mode with custom header name
client := httpclient.NewAuthClient(
    httpclient.AuthModeSimple,
    "my-key",
    httpclient.WithHeaderName("Authorization"),
)
// Requests will include:
// Authorization: my-key

For HMAC mode:

// HMAC mode with custom header names
client := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithHMACHeaders("X-Custom-Signature", "X-Request-Time", "X-Request-ID"),
)
// Requests will include custom header names

See full example: _example/03-custom-headers

Server-Side Verification

Verify authentication on the server side with the unified Verify() method:

func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Create auth config with same mode and secret as client
        auth := httpclient.NewAuthConfig(httpclient.AuthModeHMAC, "shared-secret")

        // Verify automatically selects the right verification based on mode
        // Use defaults (5 minutes max age, 10MB max body size)
        if err := auth.Verify(r); err != nil {
            http.Error(w, "Authentication failed: "+err.Error(), http.StatusUnauthorized)
            return
        }

        // Authentication is valid, proceed to next handler
        next.ServeHTTP(w, r)
    })
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/api/secure", func(w http.ResponseWriter, r *http.Request) {
        // Your secure handler code
        w.Write([]byte("Access granted"))
    })

    // Wrap with authentication middleware
    http.ListenAndServe(":8080", authMiddleware(mux))
}

Customize Verification Options (HMAC mode only):

// Strict API endpoint - 2 minute timeout, 1MB limit
if err := auth.Verify(r,
    httpclient.WithVerifyMaxAge(2*time.Minute),
    httpclient.WithVerifyMaxBodySize(1*1024*1024),
); err != nil {
    return err
}

// File upload endpoint - 10 minute timeout, 50MB limit
if err := auth.Verify(r,
    httpclient.WithVerifyMaxAge(10*time.Minute),
    httpclient.WithVerifyMaxBodySize(50*1024*1024),
); err != nil {
    return err
}

// Custom max age only (use default 10MB body limit)
if err := auth.Verify(r,
    httpclient.WithVerifyMaxAge(15*time.Minute),
); err != nil {
    return err
}

Available Verification Options:

  • WithVerifyMaxAge(duration) - Maximum age for request timestamps (default: 5 minutes)
  • WithVerifyMaxBodySize(bytes) - Maximum request body size to prevent DoS attacks (default: 10MB)

See full example: _example/04-server-verification

Automatic Authentication with RoundTripper

The simplest way to use this package - create an HTTP client that automatically signs all requests:

// Create authenticated client with automatic signing
client, err := httpclient.NewAuthClient(httpclient.AuthModeHMAC, "secret")
if err != nil {
    log.Fatal(err)
}

// Use it like a normal http.Client - authentication is automatic!
resp, err := client.Post(
    "https://api.example.com/data",
    "application/json",
    bytes.NewReader([]byte(`{"key": "value"}`)),
)

With Configuration Options:

client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTimeout(10*time.Second),
    httpclient.WithMaxBodySize(5*1024*1024), // 5MB limit
    httpclient.WithSkipAuthFunc(func(req *http.Request) bool {
        // Skip authentication for health checks
        return strings.HasPrefix(req.URL.Path, "/health")
    }),
)
if err != nil {
    log.Fatal(err)
}

Available Options:

  • WithTimeout(duration) - Set request timeout (default: 30s)
  • WithMaxBodySize(bytes) - Limit request body size (default: 10MB)
  • WithTransport(transport) - Use custom HTTP transport (must be *http.Transport if using TLS options)
  • WithSkipAuthFunc(func) - Conditionally skip authentication
  • WithHMACHeaders(sig, ts, nonce) - Custom HMAC header names
  • WithHeaderName(name) - Custom header for simple mode
  • WithRequestID(func) - Generate unique request IDs for tracing
  • WithRequestIDHeader(name) - Custom header for request ID (default: "X-Request-ID")
  • WithTLSCertFromFile(path) - Load TLS certificate from file
  • WithTLSCertFromURL(ctx, url) - Download TLS certificate from URL (with context for timeout control)
  • WithTLSCertFromBytes(pem) - Load TLS certificate from bytes
  • WithInsecureSkipVerify(bool) - Skip TLS certificate verification (testing only)
  • WithMTLSFromFile(certPath, keyPath) - Load mTLS client certificate from files
  • WithMTLSFromBytes(certPEM, keyPEM) - Load mTLS client certificate from bytes

Important: TLS options (WithTLSCert*, WithMTLS*, WithInsecureSkipVerify) cannot be combined with non-*http.Transport RoundTrippers. See Transport Chaining with TLS for details.

See full examples:

Request ID Tracking

Add unique request IDs to every request for distributed tracing, logging correlation, and debugging. Request IDs help you track requests across microservices and correlate client-side and server-side logs.

Basic Usage with UUID:

import "github.com/google/uuid"

// Create client with automatic request ID generation
client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithRequestID(func() string {
        return uuid.New().String()
    }),
)
if err != nil {
    log.Fatal(err)
}

// Every request automatically includes X-Request-ID header
resp, err := client.Get("https://api.example.com/data")
// Request includes: X-Request-ID: 550e8400-e29b-41d4-a716-446655440000

Custom Request ID Format:

var requestCounter int

client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithRequestID(func() string {
        requestCounter++
        return fmt.Sprintf("req-%d-%d", time.Now().Unix(), requestCounter)
    }),
)
// Request includes: X-Request-ID: req-1704067200-1

Custom Header Name:

// Use X-Correlation-ID instead of X-Request-ID
client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithRequestID(uuid.New().String),
    httpclient.WithRequestIDHeader("X-Correlation-ID"),
)
// Request includes: X-Correlation-ID: 550e8400-e29b-41d4-a716-446655440000

Preserving User-Provided IDs:

If a request already has a request ID header, it will be preserved:

client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithRequestID(uuid.New().String),
)

// User-provided ID takes precedence
req, _ := http.NewRequest(http.MethodGet, "https://api.example.com/data", nil)
req.Header.Set("X-Request-ID", "user-custom-id-123")
resp, err := client.Do(req)
// Request includes: X-Request-ID: user-custom-id-123 (preserved)

Works with All Features:

Request ID tracking integrates seamlessly with all authentication modes and features:

client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithRequestID(uuid.New().String),
    httpclient.WithTimeout(10*time.Second),
    httpclient.WithSkipAuthFunc(func(req *http.Request) bool {
        return strings.HasPrefix(req.URL.Path, "/health")
    }),
)
// Request ID is added to ALL requests (even when auth is skipped)

Key Features:

  • Automatic Generation: Unique ID for every request
  • Preserves User IDs: User-provided IDs are never overwritten
  • Customizable: Custom generator functions and header names
  • Always Applied: Added before authentication headers (tracks all requests)
  • Zero Overhead: No performance impact when not configured

Use Cases:

  • Distributed Tracing: Track requests across microservices
  • Log Correlation: Match client and server logs
  • Debugging: Identify specific request flows
  • Monitoring: Track request latency and errors
  • Support: Customers can provide request ID for troubleshooting

See full example: _example/10-request-id-tracking

Custom TLS Certificates

For enterprise environments with custom Certificate Authorities or self-signed certificates:

// Load certificate from file
client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTLSCertFromFile("/etc/ssl/certs/company-ca.crt"),
)
if err != nil {
    log.Fatal(err)
}

// Load certificate from URL with timeout control
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTLSCertFromURL(ctx, "https://internal-ca.company.com/ca.crt"),
)
if err != nil {
    log.Fatal(err)
}

// Load certificate from embedded content
certPEM := []byte(`-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKL0UG+mRKmdMA0GCSqGSIb3DQEBCwUAMEUx...
-----END CERTIFICATE-----`)

client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTLSCertFromBytes(certPEM),
)
if err != nil {
    log.Fatal(err)
}

// Load multiple certificates for certificate chain
client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTLSCertFromFile("/etc/ssl/certs/root-ca.crt"),
    httpclient.WithTLSCertFromFile("/etc/ssl/certs/intermediate-ca.crt"),
)
if err != nil {
    log.Fatal(err)
}

// Skip TLS verification (testing/development only - NOT RECOMMENDED for production)
client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithInsecureSkipVerify(true),
)
if err != nil {
    log.Fatal(err)
}

Key Features:

  • Load certificates from files, URLs, or byte content
  • Multiple certificates supported for chain verification
  • System certificate pool preserved (custom certs added)
  • TLS 1.2+ enforced for security
  • 1MB size limit prevents memory exhaustion attacks
  • Configuration errors cause immediate panic for fail-fast behavior
  • Skip TLS verification for testing (use with caution)

See full example: _example/08-custom-cert

mTLS (Mutual TLS) Support

Mutual TLS provides two-way authentication where both client and server verify each other's identity using certificates. This is commonly used in service-to-service communication and zero-trust architectures.

// Load mTLS certificate from files
client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithMTLSFromFile("/path/to/client.crt", "/path/to/client.key"),
)
if err != nil {
    log.Fatal(err)
}

// Load mTLS certificate from byte content
certPEM, _ := os.ReadFile("client.crt")
keyPEM, _ := os.ReadFile("client.key")

client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithMTLSFromBytes(certPEM, keyPEM),
)
if err != nil {
    log.Fatal(err)
}

// Combine mTLS with custom CA certificate
client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTLSCertFromFile("/path/to/ca.crt"),              // Trust server's CA
    httpclient.WithMTLSFromFile("/path/to/client.crt", "/path/to/client.key"), // Client cert
)
if err != nil {
    log.Fatal(err)
}

Key Features:

  • Load client certificates from files or byte content
  • Automatic certificate validation (cert/key pair must match)
  • Combine with custom CA certificates for complete mTLS setup
  • Error reporting for invalid certificates or missing files
  • Compatible with all other client options

See full example: _example/09-mtls

Transport Chaining with TLS

When using custom middleware (logging, metrics, tracing, etc.) with TLS options, you must provide an *http.Transport, not any other RoundTripper implementation.

Why this limitation exists:

TLS configuration (custom CA certificates, mTLS, InsecureSkipVerify) can only be applied to *http.Transport. Non-Transport RoundTrippers (like logging or metrics middleware) cannot have TLS settings directly applied to them.

What happens if you violate this:

// ❌ This will return an error
loggingMiddleware := &MyLoggingRoundTripper{
    Next: http.DefaultTransport,
}

client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTransport(loggingMiddleware),  // Non-Transport RoundTripper
    httpclient.WithTLSCertFromFile("/path/to/ca.crt"), // TLS option
)
// Error: "TLS options (WithTLSCert*, WithMTLS*, WithInsecureSkipVerify) cannot be combined
//         with non-Transport RoundTrippers provided via WithTransport()..."

Solution 1: Configure TLS in your Transport (Recommended)

// ✅ Configure TLS in *http.Transport, then wrap with middleware
certPool := x509.NewCertPool()
certPEM, _ := os.ReadFile("/path/to/ca.crt")
certPool.AppendCertsFromPEM(certPEM)

tlsTransport := &http.Transport{
    TLSClientConfig: &tls.Config{
        RootCAs: certPool,
    },
}

// Pass the Transport with TLS configured
client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTransport(tlsTransport),
)

// Then wrap the client's Transport with your middleware
client.Transport = &LoggingRoundTripper{
    Next: client.Transport, // Wraps authRoundTripper -> tlsTransport
}

Solution 2: Use *http.Transport only

// ✅ Use *http.Transport with TLS options
customTransport := &http.Transport{
    MaxIdleConns: 100,
    IdleConnTimeout: 90 * time.Second,
}

client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTransport(customTransport),        // *http.Transport is OK
    httpclient.WithTLSCertFromFile("/path/to/ca.crt"), // TLS options work
)

Key Points:

  • TLS options work with *http.Transport or no custom transport
  • TLS options cannot be combined with non-Transport RoundTrippers
  • You can wrap the client's Transport with middleware after creation
  • The library provides clear error messages to guide you

See full example: _example/07-transport-chaining

Features

  • Automatic Authentication: RoundTripper-based client signs requests automatically
  • Flexible Configuration: Option Pattern for easy customization (timeout, body limits, etc.)
    • Client Options: WithTimeout, WithMaxBodySize, WithTransport, WithSkipAuthFunc, WithRequestID, etc.
    • Verification Options: WithVerifyMaxAge, WithVerifyMaxBodySize for per-endpoint control
  • Multiple Authentication Strategies: Choose between none, simple, or HMAC modes
  • Request ID Tracking: Generate unique IDs for distributed tracing and log correlation
    • Automatic generation with custom functions (UUID, timestamp, etc.)
    • Preserves user-provided request IDs
    • Customizable header names (default: X-Request-ID)
    • Works with all authentication modes
  • Custom TLS Certificates: Load certificates from files, URLs, or embedded content
  • mTLS Support: Client certificate authentication for mutual TLS
  • Enterprise PKI Support: Trust custom Certificate Authorities and self-signed certificates
  • Cryptographic Security: HMAC-SHA256 signatures with constant-time comparison
  • Replay Attack Protection: Timestamp validation prevents reuse of old requests
  • Query Parameter Security: Include URL parameters in signature to prevent tampering
  • Request Integrity: Signature covers method, path, query, and body
  • Body Preservation: Request body is restored after verification for downstream handlers
  • Transport Chaining: Compatible with logging, metrics, and custom transports
  • Conditional Authentication: Skip auth for specific endpoints (e.g., health checks)
  • DoS Protection: Configurable body size limits prevent memory exhaustion attacks
    • Default: 10MB limit for verification
    • Per-endpoint customization: strict APIs (1MB) vs. file uploads (50MB)
    • Early rejection with io.LimitReader for safe, bounded reading
  • Customizable Headers: Override default header names to match your API conventions
  • Dual Purpose: Same package for client signing and server verification
  • Zero Config Defaults: Sensible defaults with optional customization
  • Production Ready: 90%+ test coverage, comprehensive linting, and security scanning

Security

HMAC Signature Calculation

The HMAC signature includes all critical request components:

message = timestamp + method + path + query + body
signature = HMAC-SHA256(secret, message)

Example:

Request: POST /api/users?role=admin
Body: {"name": "John"}
Timestamp: 1704067200
Secret: my-secret

Message: "1704067200POST/api/users?role=admin{\"name\":\"John\"}"
Signature: HMAC-SHA256("my-secret", message)
Protection Features
  1. Replay Attack Prevention

    • Each request includes a timestamp
    • Server validates timestamp is within acceptable window (default: 5 minutes)
    • Old signatures cannot be reused
  2. Request Tampering Detection

    • Any modification to method, path, query, or body invalidates signature
    • Cryptographic verification ensures request integrity
  3. Query Parameter Security

    • Query parameters are included in signature calculation
    • Prevents attackers from adding/modifying/removing parameters
  4. Constant-Time Comparison

    • Uses hmac.Equal() to prevent timing attacks
    • Secure against side-channel attacks
  5. Memory Exhaustion Protection (DoS Prevention)

    • Request Body Size Limits: Configurable per-endpoint (default: 10MB)
      • Prevents attackers from sending massive payloads
      • Uses io.LimitReader for safe, bounded reading
      • Returns clear error message when limit exceeded
    • TLS Certificate Size Limits: Maximum 1MB for certificate files
    • Fail-Fast Validation: Early rejection before processing malicious requests

    Example Configuration:

    // Strict API: 1MB limit
    auth.Verify(req, httpclient.WithVerifyMaxBodySize(1*1024*1024))
    
    // File upload API: 50MB limit
    auth.Verify(req, httpclient.WithVerifyMaxBodySize(50*1024*1024))
    
Security Best Practices
  • Use HTTPS (TLS) for all requests to protect secrets in transit
  • Rotate shared secrets regularly
  • Use strong, random secrets (minimum 32 bytes)
  • Set appropriate timestamp validation windows (default 5 minutes)
  • Monitor and log authentication failures
  • Use HMAC mode for production environments

API Reference

Types
AuthConfig

Main configuration struct for authentication:

type AuthConfig struct {
    Mode            string // "none", "simple", "hmac" or "github"
    Secret          string // Shared secret key
    HeaderName      string // Custom header for simple mode (default: "X-API-Secret")
    SignatureHeader string // Signature header for HMAC (default: "X-Signature")
    TimestampHeader string // Timestamp header for HMAC (default: "X-Timestamp")
    NonceHeader     string // Nonce header for HMAC (default: "X-Nonce")
}
Constants

Authentication Modes:

const (
    AuthModeNone   = "none"   // No authentication
    AuthModeSimple = "simple" // Simple API secret in header
    AuthModeHMAC   = "hmac"   // HMAC-SHA256 signature
    AuthModeGitHub = "github" // GitHub webhook-style HMAC-SHA256
)

Default Header Names:

const (
    DefaultAPISecretHeader       = "X-API-Secret"        // Simple mode
    DefaultSignatureHeader       = "X-Signature"         // HMAC mode
    DefaultTimestampHeader       = "X-Timestamp"         // HMAC mode
    DefaultNonceHeader           = "X-Nonce"             // HMAC mode
    DefaultGitHubSignatureHeader = "X-Hub-Signature-256" // GitHub mode
    DefaultRequestIDHeader       = "X-Request-ID"        // Request tracking
)
Functions
NewClient
func NewClient(opts ...ClientOption) (*http.Client, error)

Creates a standard HTTP client without authentication. This is a convenience wrapper around NewAuthClient with AuthModeNone.

Parameters:

  • opts: Optional configuration (timeout, TLS certs, request ID, etc.)

Returns: Configured *http.Client without authentication, or error if any option fails

Example:

// Basic usage
client, err := httpclient.NewClient()
if err != nil {
    log.Fatal(err)
}

// With custom configuration
client, err := httpclient.NewClient(
    httpclient.WithTimeout(10*time.Second),
    httpclient.WithTLSCertFromFile("/etc/ssl/certs/ca.crt"),
)
NewAuthClient
func NewAuthClient(mode, secret string, opts ...ClientOption) (*http.Client, error)

Creates an HTTP client with automatic authentication. All requests are signed automatically based on the configured mode.

Parameters:

  • mode: Authentication mode (AuthModeNone, AuthModeSimple, AuthModeHMAC, or AuthModeGitHub)
  • secret: Shared secret key
  • opts: Optional configuration (timeout, body limits, custom headers, etc.)

Returns: Configured *http.Client with automatic authentication, or error if any option fails

Example:

client, err := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTimeout(10*time.Second),
    httpclient.WithMaxBodySize(5*1024*1024),
)
if err != nil {
    log.Fatal(err)
}
Client Options

Configure NewAuthClient behavior:

General Options:

  • WithTimeout(duration) - Request timeout (default: 30s)
  • WithMaxBodySize(bytes) - Max body size (default: 10MB, set 0 for unlimited)
  • WithTransport(transport) - Custom base transport (must be *http.Transport if using TLS options)
  • WithSkipAuthFunc(func(*http.Request) bool) - Skip auth conditionally

Authentication Options:

  • WithHMACHeaders(sig, ts, nonce string) - Custom HMAC header names
  • WithHeaderName(name string) - Custom header for simple mode

Request Tracking Options:

  • WithRequestID(func() string) - Generate unique request IDs for tracing
  • WithRequestIDHeader(name string) - Custom header name for request ID (default: "X-Request-ID")

TLS Certificate Options:

  • WithTLSCertFromFile(path string) - Load certificate from file path
  • WithTLSCertFromURL(ctx context.Context, url string) - Download certificate from URL with context for timeout control
  • WithTLSCertFromBytes(certPEM []byte) - Load certificate from byte content
  • WithInsecureSkipVerify(skip bool) - Skip TLS certificate verification (WARNING: Use only for testing/development, never in production)

Example:

client := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithTimeout(30*time.Second),
    httpclient.WithTLSCertFromFile("/etc/ssl/certs/company-ca.crt"),
)

// For testing with self-signed certificates (NOT for production)
testClient := httpclient.NewAuthClient(
    httpclient.AuthModeHMAC,
    "secret",
    httpclient.WithInsecureSkipVerify(true),
)
NewAuthConfig
func NewAuthConfig(mode, secret string) *AuthConfig

Creates a new AuthConfig with default header names. This is primarily used for server-side verification with the Verify() method.

Parameters:

  • mode: Authentication mode (AuthModeNone, AuthModeSimple, or AuthModeHMAC)
  • secret: Shared secret key (must match the client's secret)

Returns: Configured *AuthConfig with defaults

Example:

// Server-side verification
auth := httpclient.NewAuthConfig(httpclient.AuthModeHMAC, "shared-secret")
if err := auth.Verify(req); err != nil {
    http.Error(w, "Authentication failed", http.StatusUnauthorized)
    return
}
Verify
func (c *AuthConfig) Verify(req *http.Request, opts ...VerifyOption) error

Verifies authentication from an HTTP request (server-side validation). This is the unified verification method that automatically selects the appropriate verification logic based on the configured authentication mode.

Supported Modes:

  • AuthModeNone: No verification performed, returns nil immediately
  • AuthModeSimple: Verifies the API secret in the configured header
  • AuthModeHMAC: Verifies HMAC signature with timestamp and body validation

Parameters:

  • req: HTTP request to verify
  • opts: Optional configuration (only applies to HMAC mode)

Returns: Error if verification fails or signature is invalid

Available Options (HMAC mode only):

  • WithVerifyMaxAge(duration) - Maximum age for request timestamps (default: 5 minutes)
  • WithVerifyMaxBodySize(bytes) - Maximum request body size to prevent DoS attacks (default: 10MB)

Examples:

// Simple mode verification
auth := httpclient.NewAuthConfig(httpclient.AuthModeSimple, "secret")
err := auth.Verify(req)

// HMAC mode with defaults (5 minutes, 10MB)
auth := httpclient.NewAuthConfig(httpclient.AuthModeHMAC, "secret")
err := auth.Verify(req)

// HMAC mode with custom max age only
err := auth.Verify(req,
    httpclient.WithVerifyMaxAge(10*time.Minute),
)

// HMAC mode with custom body size limit only
err := auth.Verify(req,
    httpclient.WithVerifyMaxBodySize(5*1024*1024),
)

// HMAC mode with multiple options
err := auth.Verify(req,
    httpclient.WithVerifyMaxAge(10*time.Minute),
    httpclient.WithVerifyMaxBodySize(50*1024*1024),
)

Security Features (HMAC mode):

  • Body Size Limit: Prevents memory exhaustion DoS attacks (default: 10MB)
  • Timestamp Validation: Rejects requests older than max age (default: 5 minutes)
  • Clock Skew Protection: Rejects requests with future timestamps beyond max age
  • Constant-Time Comparison: Uses hmac.Equal() to prevent timing attacks
  • Body Preservation: Request body is restored for subsequent handlers

Testing

Run tests with coverage:

make test

Run linting and formatting:

make lint
make fmt
Test Coverage

The package includes comprehensive tests covering:

  • All three authentication modes
  • Custom header names
  • Signature calculation consistency
  • Server-side verification
  • Invalid signature rejection
  • Timestamp expiration
  • Missing header validation
  • Body preservation after verification
  • Query parameter tampering prevention
  • Body size limit protection (new)
    • Requests within limit accepted
    • Requests exceeding limit rejected
    • Exact limit boundary testing
    • Default 10MB limit validation
    • Custom size limit configuration
    • Multiple options combination
  • TLS certificate loading from files, URLs, and bytes
  • Multiple certificate chain verification
  • Certificate error handling
  • Options Pattern API usage

Coverage: 90.1% of statements

View coverage report:

go test -coverprofile=coverage.txt
go tool cover -html=coverage.txt

Development

Prerequisites
  • Go 1.24 or higher
  • Make (optional, for convenience)
Project Structure
.
├── auth.go              # Core authentication implementation
├── auth_test.go         # Authentication tests (560+ lines)
├── client.go            # RoundTripper-based HTTP client
├── client_test.go       # Client tests (660+ lines)
├── cert_test.go         # TLS certificate tests (360+ lines)
├── go.mod               # Module definition
├── Makefile            # Build automation
├── .golangci.yml       # Linting configuration
├── _example/           # Runnable examples
│   ├── 01-simple-auth/           # Simple API key authentication
│   ├── 02-hmac-auth/             # HMAC signature authentication
│   ├── 03-custom-headers/        # Custom header names
│   ├── 04-server-verification/   # Server-side verification
│   ├── 05-roundtripper-client/   # Automatic authentication
│   ├── 06-options-showcase/      # Configuration options
│   ├── 07-transport-chaining/    # Transport composition
│   ├── 08-custom-cert/           # Custom TLS certificates
│   ├── 09-mtls/                  # Mutual TLS authentication
│   └── 10-request-id-tracking/   # Request ID tracking and tracing
└── .github/workflows/  # CI/CD pipelines
    ├── testing.yml     # Multi-platform testing
    ├── security.yml    # Trivy security scanning
    └── codeql.yml      # Code quality analysis
Makefile Commands
make test    # Run tests with coverage
make fmt     # Format code with golangci-lint
make lint    # Run linting checks
make clean   # Remove coverage artifacts
make help    # Show all commands
CI/CD Pipeline
  • Testing: Runs on Go 1.24 and 1.25, on Ubuntu and macOS
  • Security: Daily Trivy scans for vulnerabilities
  • Code Quality: CodeQL analysis for Go best practices
  • Coverage: Automatic upload to Codecov

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run tests and linting (make test lint)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request
Code Standards
  • Follow Go best practices and idioms
  • Maintain test coverage above 80%
  • Pass all linting checks (golangci-lint)
  • Add tests for new features
  • Update documentation as needed

License

This project is licensed under the MIT License - see the LICENSE file for details.

Copyright (c) 2026 Bo-Yi Wu

Author

Support this project:

Donate

Documentation

Index

Constants

View Source
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

View Source
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

View Source
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

View Source
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

Directories

Path Synopsis
_example

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL