Documentation
¶
Index ¶
- func CORS(cfg CORSConfig) func(http.Handler) http.Handler
- func CachePrivate(maxAge time.Duration) func(http.Handler) http.Handler
- func CachePublic(maxAge time.Duration) func(http.Handler) http.Handler
- func Handler() http.Handler
- func Logs(cfg Config) func(http.Handler) http.Handler
- func MaxBodySize(limit int64) func(http.Handler) http.Handler
- func Metrics(c *Collectors, cfg MetricsConfig) func(http.Handler) http.Handler
- func NoCache() func(http.Handler) http.Handler
- func QueryParams[T any](r *http.Request) T
- func RateLimit(cfg RateLimitConfig) func(http.Handler) http.Handler
- func RealIP() func(http.Handler) http.Handler
- func Recover(logger *zap.Logger) func(http.Handler) http.Handler
- func RequestID(cfg ...RequestIDConfig) func(http.Handler) http.Handler
- func RequestIDFromCtx(ctx context.Context) string
- func SecurityHeaders() func(http.Handler) http.Handler
- func Timeout(d time.Duration) func(http.Handler) http.Handler
- func WithParams[T any](strict ...bool) func(http.Handler) http.Handler
- type APIKeyHook
- type CORSConfig
- type Collectors
- type Config
- type JWTHook
- type KeyExtractorFunc
- type KeyFunc
- type MetricsConfig
- type Middleware
- type RateLimitConfig
- type RequestIDConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CORS ¶
func CORS(cfg CORSConfig) func(http.Handler) http.Handler
CORS returns a fully configured CORS middleware using rs/cors under the hood.
r.Use(mw.CORS(mw.CORSConfig{
AllowedOrigins: []string{"https://app.example.com"},
AllowCredentials: true,
}))
func CachePrivate ¶
CachePrivate sets Cache-Control to private with the given max-age. Use on user-specific responses that the browser may cache but proxies must not.
r.With(mw.CachePrivate(1 * time.Minute)).Get("/dashboard/stats", handler)
func CachePublic ¶
CachePublic sets Cache-Control to public with the given max-age. Use on responses that are safe to cache by anyone (CDN, browser, proxy).
r.With(mw.CachePublic(5 * time.Minute)).Get("/assets/config", handler)
func Logs ¶
Logs returns structured request logging middleware. It reads the request ID from the header set by the RequestID middleware (or any upstream proxy).
func MaxBodySize ¶
MaxBodySize limits the request body to limit bytes. Requests with bodies exceeding the limit will fail when the handler reads past it. Only applied when the request body is non-nil.
func Metrics ¶
func Metrics(c *Collectors, cfg MetricsConfig) func(http.Handler) http.Handler
Metrics returns an HTTP middleware that records request count and duration.
func NoCache ¶
NoCache sets headers that instruct clients and proxies never to cache the response. Use on endpoints that always return fresh data (auth, user-specific, etc).
r.With(mw.NoCache()).Get("/me", handler)
func QueryParams ¶
QueryParams extracts the parsed query params from the request context.
func RateLimit ¶
func RateLimit(cfg RateLimitConfig) func(http.Handler) http.Handler
RateLimit returns a token-bucket rate limiting middleware. Each unique key (by default, the client IP) gets its own limiter. Requests that exceed the limit receive 429 Too Many Requests.
// 100 req/s per IP, burst of 20
r.Use(mw.RateLimit(mw.RateLimitConfig{RPS: 100, Burst: 20}))
// per API key
r.Use(mw.RateLimit(mw.RateLimitConfig{
RPS: 50,
Burst: 10,
KeyExtractor: func(r *http.Request) string {
return r.Header.Get("X-API-Key")
},
}))
func RealIP ¶
RealIP rewrites r.RemoteAddr with the real client IP, in order:
- CF-Connecting-IP — set by Cloudflare, cannot be spoofed by clients
- X-Forwarded-For — leftmost (client) IP, used for direct/non-Cloudflare traffic
- RemoteAddr — unchanged fallback for direct connections with no proxy headers
Place this as early as possible in the middleware chain so that downstream middleware (e.g. RateLimit) see the correct IP.
r.Use(mw.RealIP())
func Recover ¶
Recover catches panics, logs them via zap with the full stack trace, and responds with 500 Internal Server Error.
r.Use(mw.Recover(logger))
func RequestID ¶
func RequestID(cfg ...RequestIDConfig) func(http.Handler) http.Handler
RequestID adds a request ID to the context and response headers. If the incoming request already carries one in the configured header it is reused; otherwise a new UUID v7 is generated (falling back to v4 on error).
func RequestIDFromCtx ¶
RequestIDFromCtx retrieves the request ID stored by the RequestID middleware.
func SecurityHeaders ¶
SecurityHeaders sets a baseline of security-related response headers suitable for APIs. For HTML-serving applications consider also adding Content-Security-Policy and Permissions-Policy.
r.Use(mw.SecurityHeaders())
func Timeout ¶
Timeout sets a deadline on the request context. Handlers must respect ctx.Done() to honour the timeout — this is especially important for SSE and WebSocket handlers which own their own read/write loops. Pass 0 to use the default of 30s.
r.Use(mw.Timeout(10 * time.Second)) r.Use(mw.Timeout(0)) // 30s default
func WithParams ¶
WithParams parses, converts, and validates query params into T using fun_query tags. Pass strict=true to reject any query param not declared in T.
Tags:
fun_query:"key" string param, optional fun_query:"key,required" param must be present and non-empty fun_query:"key,default=val" fallback value if absent or empty
Supported field types: string, int, int64, bool, uuid.UUID
Usage:
type ListParams struct {
Status string `fun_query:"status,default=active"`
Page int `fun_query:"page,default=1"`
ID uuid.UUID `fun_query:"id,required"`
}
r.With(middlewares.WithParams[ListParams]()).Get("/items", h.List)
r.With(middlewares.WithParams[ListParams](true)).Get("/items", h.List) // strict
// in handler:
params := middlewares.Params[ListParams](r)
Types ¶
type APIKeyHook ¶
APIKeyHook is called with the raw key extracted from X-API-Key. Lookup, hashing, and ctx enrichment are fully the caller's responsibility. Returning a non-nil error rejects the request with 401.
type CORSConfig ¶
type CORSConfig struct {
// AllowedOrigins is the list of origins allowed to make cross-origin requests.
// Use []string{"*"} to allow all. Required.
AllowedOrigins []string
// AllowedMethods defaults to GET, POST, PUT, PATCH, DELETE, OPTIONS if empty.
AllowedMethods []string
// AllowedHeaders defaults to Content-Type, Authorization, X-Request-ID, X-API-Key if empty.
AllowedHeaders []string
// ExposedHeaders are headers the browser is allowed to read from the response.
ExposedHeaders []string
// AllowCredentials sets Access-Control-Allow-Credentials.
// Note: cannot be used with AllowedOrigins: ["*"].
AllowCredentials bool
// MaxAge sets how long the preflight result can be cached.
// Defaults to 10 minutes if zero.
MaxAge time.Duration
}
CORSConfig exposes the options you actually need to touch. Everything else is defaulted to safe, permissive-for-APIs values.
type Collectors ¶
type Collectors struct {
RequestsTotal *prometheus.CounterVec
RequestDuration *prometheus.HistogramVec
}
Collectors holds the Prometheus metrics registered by this package. Use NewCollectors to create and register them, then pass to Middleware.
func NewCollectors ¶
func NewCollectors(reg prometheus.Registerer) (*Collectors, error)
NewCollectors creates and registers Prometheus metrics with the given registerer. Pass prometheus.DefaultRegisterer if you don't have a custom one.
type Config ¶
type Config struct {
// Logger is the zap logger to write to. Required.
Logger *zap.Logger
// SkipPrefixes lists URL path prefixes that will not be logged.
// e.g. []string{"/admin/asynq", "/healthz"}
SkipPrefixes []string
// RequestIDHeader is the header name to read the request ID from.
// Defaults to "X-Request-ID".
RequestIDHeader string
}
Config controls logger behavior.
type JWTHook ¶
JWTHook is called after the package successfully verifies and parses a JWT. It may enrich ctx (e.g. inject a subject) and must return the (possibly new) ctx. Returning a non-nil error rejects the request with 401.
type KeyExtractorFunc ¶
KeyExtractorFunc extracts a rate limit key from the request. The returned string is used to bucket requests — typically an IP or API key.
type KeyFunc ¶
KeyFunc returns the key used to verify a token, given its parsed (but unverified) form while also taking a context. Mirrors jwt.Keyfunc so callers can reuse existing implementations.
type MetricsConfig ¶
type MetricsConfig struct {
// SkipPrefixes lists URL path prefixes that will not be instrumented.
// e.g. []string{"/metrics", "/swagger", "/healthz"}
SkipPrefixes []string
}
MetricsConfig controls which paths are skipped by the middleware.
type Middleware ¶
type Middleware[C jwt.Claims] struct { KeyFunc KeyFunc[C] // contains filtered or unexported fields }
Middleware holds all auth configuration. Build once with New, use everywhere.
func New ¶
func New[C jwt.Claims](keyFunc KeyFunc[C], jwtHook JWTHook[C], apiKeyHook APIKeyHook) *Middleware[C]
New creates an auth middleware.
- keyFunc: provides the verification key (e.g. []byte HMAC secret, *rsa.PublicKey)
- jwtHook: called after successful JWT verification to enrich the ctx
- apiKeyHook: called with the raw API key — lookup and ctx enrichment are yours
TracerName optionally overrides the OTel tracer name (defaults to "trimid/auth").
authMW := auth.New[*MyClaims](keyFunc, jwtHook, apiKeyHook)
r.With(authMW.JWT()).Get("/me", meHandler)
r.With(authMW.APIKey()).Post("/ingest", ingestHandler)
r.With(authMW.AnyAuth()).Post("/events", eventHandler)
func (*Middleware[C]) APIKey ¶
func (m *Middleware[C]) APIKey() func(http.Handler) http.Handler
APIKey returns a middleware that:
- Extracts the raw key from X-API-Key.
- Calls the configured APIKeyHook — lookup, hashing, and ctx enrichment are yours.
Any failure at any step responds 401 and stops the chain.
func (*Middleware[C]) AnyAuth ¶
func (m *Middleware[C]) AnyAuth() func(http.Handler) http.Handler
AnyAuth tries API key first (if X-API-Key is present), then Bearer JWT. At least one must succeed; if neither header is present the request is rejected.
func (*Middleware[C]) JWT ¶
func (m *Middleware[C]) JWT() func(http.Handler) http.Handler
JWT returns a middleware that:
- Extracts the Bearer token from Authorization.
- Verifies and parses it into C using the configured KeyFunc.
- Calls the configured JWTHook with the parsed claims.
Any failure at any step responds 401 and stops the chain.
type RateLimitConfig ¶
type RateLimitConfig struct {
// RPS is the number of requests per second allowed per key.
RPS rate.Limit
// Burst is the maximum burst size above RPS.
Burst int
// KeyExtractor determines how to bucket requests.
// Defaults to RemoteAddr (IP-based) if nil.
KeyExtractor KeyExtractorFunc
}
RateLimitConfig configures the rate limiter.
type RequestIDConfig ¶
type RequestIDConfig struct {
// Header is the header to read/write the request ID.
// Defaults to "X-Request-ID".
Header string
}
RequestIDConfig controls RequestID middleware behavior.