Help us shape the future of Go! Take the 2026 Go Developer Survey

middleware

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Oct 28, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package middleware provides HTTP middleware for the API server.

Index

Constants

View Source
const CSRFHeaderName = "X-CSRF-Token"

CSRF protects the COOKIE-authenticated JSON API (ENABLE_COOKIE_AUTH, default off; see server/handlers.go) with a synchronizer token bound to the API session cookie: the token is an HMAC of the cookie value under a server key. Page script cannot read the HttpOnly cookie, so it can neither compute nor fetch the token; login returns it in the response body. Unsafe cookie requests must also be same-origin per Sec-Fetch-Site and Origin. Requests that were not authenticated by the cookie (bearer, API key) are exempt: bearer auth is not CSRF-vulnerable.

Variables

View Source
var CSRFCookieName = "hatamoto_csrf"

CSRFCookieName is the double-submit cookie name. Like auth.SessionCookieName it keeps the historical default and is switched once at boot.

View Source
var TraceHook func(r *http.Request, tag string)

TraceHook, when set, is called with a short tag each time a request enters one of the gates (auth, CSRF, role, rate limit; the server adds tenant and capture). Tests use it to pin which gates guard which route; production never sets it. It observes only: every gate still enforces.

Functions

func APICSRFToken

func APICSRFToken(key []byte, cookieToken string) string

APICSRFToken returns the CSRF token bound to the API session cookie value.

func APIKeyAuthMiddleware

func APIKeyAuthMiddleware(apiKeyService *auth.APIKeyService, rateLimiter *APIKeyRateLimiter) func(http.Handler) http.Handler

APIKeyAuthMiddleware validates API keys from the X-API-Key header. It sets tenant context similar to session auth, enabling RLS.

func AuthMiddleware

func AuthMiddleware(validateBearer, validateCookie SessionValidator, cookieAuth bool) func(http.Handler) http.Handler

AuthMiddleware authenticates a request by its server-side session: the opaque token in Authorization: Bearer (checked by validateBearer), else (when cookieAuth) the HttpOnly API session cookie (checked by validateCookie, which must accept API-kind sessions only). The admin form session cookie is never read here. Anything else is a 401.

func AuthOrAPIKey

func AuthOrAPIKey(v APIKeyValidator, limiter APIKeyAllower, next func(http.Handler) http.Handler) func(http.Handler) http.Handler

AuthOrAPIKey authenticates a request that carries an X-API-Key header as an API key, restricted to keyRoutes; requests without the header go to next (the regular session auth) unchanged. A request with both a header and a session cookie is key-authenticated.

Key requests run with synthesised editor claims for the key's creator (never superadmin) so existing handlers work unmodified, plus the API key and AuthTypeAPIKey in the context (so CSRF can be skipped and saves attributed).

func CSRF

func CSRF(key []byte) func(http.Handler) http.Handler

CSRF returns middleware enforcing the synchronizer check on unsafe methods when the request was authenticated via the API session cookie.

func ClearCSRFCookie

func ClearCSRFCookie(w http.ResponseWriter, secure bool)

ClearCSRFCookie expires the CSRF cookie (logout). Legacy-named cookies are expired by the server's legacy cookie middleware.

func ContextWithClaims

func ContextWithClaims(ctx context.Context, claims *auth.Claims) context.Context

ContextWithClaims returns a copy of ctx carrying the given claims. Exposed so tests (and any in-process caller) can populate the same context slot the auth middleware uses, without importing the unexported context key.

func GetAPICookieToken

func GetAPICookieToken(ctx context.Context) (string, bool)

GetAPICookieToken returns the API session cookie token the request was authenticated with. It is absent for bearer and API-key requests, which is what lets CSRF protect cookie-authenticated requests only.

func GetAPIKey

func GetAPIKey(ctx context.Context) (*auth.APIKey, bool)

GetAPIKey retrieves the API key from the request context.

func GetClaims

func GetClaims(ctx context.Context) (*auth.Claims, bool)

GetClaims retrieves the authenticated principal from the request context.

func GetClientIP

func GetClientIP(r *http.Request) string

GetClientIP extracts the client IP from the request as a string. Honours X-Forwarded-For / X-Real-IP only when the immediate RemoteAddr is in the trusted-proxy CIDR list. Exported so other packages can share a single trust policy.

func GetTenantID

func GetTenantID(ctx context.Context) (uuid.UUID, bool)

GetTenantID is retained for callers that historically asked "is the current request authenticated as a tenant principal?". Post-Path-B the tenant dimension is gone; the second return value is the only useful signal. Returns (uuid.Nil, true) when the request carries an admin claim or API key, (uuid.Nil, false) otherwise.

func GetUserID

func GetUserID(ctx context.Context) (uuid.UUID, bool)

GetUserID extracts user ID from context (shorthand).

func IPBucket

func IPBucket(ip string) string

IPBucket is the key a client address is limited under: the address itself, or for IPv6 its /64, so one host with a whole prefix gets one bucket, not 2^64.

func IsTrustedProxy

func IsTrustedProxy(remoteAddr string) bool

IsTrustedProxy reports whether remoteAddr (host:port or bare IP) is a trusted proxy, i.e. whether its X-Forwarded-* headers may be believed.

func NewCSRFToken

func NewCSRFToken() string

NewCSRFToken returns a fresh random CSRF token.

func RecoveryLogger

func RecoveryLogger(logger *slog.Logger, redact func(path string) string) func(http.Handler) http.Handler

RecoveryLogger recovers from panics and logs them. redact works as in RequestLogger.

func RequestLogger

func RequestLogger(logger *slog.Logger, redact func(path string) string) func(http.Handler) http.Handler

RequestLogger logs HTTP requests with structured logging. redact maps the request path to the string that is logged (nil logs it unchanged); it runs before the handler so a prefix swapped mid-request is still the one redacted.

func RequireAPIKeyScope

func RequireAPIKeyScope(scope auth.APIKeyScope) func(http.Handler) http.Handler

RequireAPIKeyScope middleware ensures the API key has the required scope.

func RequireRole

func RequireRole(roles ...string) func(http.Handler) http.Handler

RequireRole middleware ensures the user has one of the specified roles.

func SetCSRFCookie

func SetCSRFCookie(w http.ResponseWriter, secure bool) string

SetCSRFCookie mints a token and sets it as a NON-HttpOnly cookie (the SPA must read it to echo in the header). SameSite=Strict, Secure configurable. Returns the token so callers may also surface it in a response body if desired.

func SetTrustedProxies

func SetTrustedProxies(cidrs []string)

SetTrustedProxies replaces the trusted-proxy CIDR list (HATAMOTO_TRUSTED_PROXIES). Call it once at startup, before serving; an empty list keeps the loopback-only default.

func Trace

func Trace(r *http.Request, tag string)

Trace lets the server package tag its own middleware.

func UseNeutralCSRFCookieName

func UseNeutralCSRFCookieName(secure bool)

UseNeutralCSRFCookieName sets "__Host-c" when secure, "c" otherwise (see auth.UseNeutralCookieNames for why plain-HTTP dev cannot use the prefix).

Types

type APIKeyAllower

type APIKeyAllower interface {
	Allow(keyID uuid.UUID, rateLimit int) bool
}

APIKeyAllower is the slice of APIKeyRateLimiter that AuthOrAPIKey needs.

type APIKeyRateLimiter

type APIKeyRateLimiter struct {
	// contains filtered or unexported fields
}

APIKeyRateLimiter implements per-key rate limiting for API keys.

func NewAPIKeyRateLimiter

func NewAPIKeyRateLimiter() *APIKeyRateLimiter

NewAPIKeyRateLimiter creates a new API key rate limiter.

func (*APIKeyRateLimiter) Allow

func (rl *APIKeyRateLimiter) Allow(keyID uuid.UUID, rateLimit int) bool

Allow checks if a request is allowed for the given API key. Returns true if allowed, false if rate limited.

func (*APIKeyRateLimiter) Stop

func (rl *APIKeyRateLimiter) Stop()

Stop terminates the background cleanup goroutine.

type APIKeyValidator

type APIKeyValidator interface {
	ValidateKey(ctx context.Context, plainKey string) (*auth.APIKey, error)
	RecordUsage(ctx context.Context, keyID uuid.UUID, ipAddress string) error
}

APIKeyValidator is the slice of auth.APIKeyService that AuthOrAPIKey needs.

type AuthType

type AuthType string

AuthType represents the type of authentication used.

const (
	AuthTypeAPIKey AuthType = "api_key"
)

func GetAuthType

func GetAuthType(ctx context.Context) AuthType

GetAuthType returns the authentication type used for the request.

type RateLimiter

type RateLimiter struct {
	// contains filtered or unexported fields
}

RateLimiter implements per-IP rate limiting.

func APIRateLimiter

func APIRateLimiter() *RateLimiter

APIRateLimiter is a general rate limiter for API endpoints.

func AuthRateLimiter

func AuthRateLimiter() *RateLimiter

AuthRateLimiter is a stricter rate limiter for auth endpoints.

func NewRateLimiter

func NewRateLimiter(rps float64, burst int) *RateLimiter

NewRateLimiter creates a new rate limiter. rate: requests per second burst: maximum burst size

func (*RateLimiter) Allow

func (rl *RateLimiter) Allow(key string) bool

Allow reports whether key may make a request now; it is the limiter's own bucket logic for callers that choose the key themselves (a session, say).

func (*RateLimiter) ByIPv6Prefix

func (rl *RateLimiter) ByIPv6Prefix() *RateLimiter

ByIPv6Prefix makes the limiter count an IPv6 client by its /64 instead of its single address (see IPBucket) and returns it. Used where a host with a whole prefix must not get a bucket per address, such as the public demo.

func (*RateLimiter) Middleware

func (rl *RateLimiter) Middleware(next http.Handler) http.Handler

Middleware returns a rate limiting middleware.

func (*RateLimiter) Stop

func (rl *RateLimiter) Stop()

Stop terminates the background cleanup goroutine.

type SessionValidator

type SessionValidator func(ctx context.Context, token string) (*auth.Claims, error)

SessionValidator resolves an opaque session token to the principal it belongs to (server-side session lookup).

Jump to

Keyboard shortcuts

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