// Package auth provides simple HTTP basic authentication middleware for the CID hub. package auth import ( "crypto/subtle" "net/http" ) // BasicAuth wraps an HTTP handler with basic auth protection. func BasicAuth(username, password string, next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if username == "" { // No auth configured next(w, r) return } user, pass, ok := r.BasicAuth() if !ok { w.Header().Set("WWW-Authenticate", `Basic realm="CID Hub"`) http.Error(w, "Unauthorized", http.StatusUnauthorized) return } userMatch := subtle.ConstantTimeCompare([]byte(user), []byte(username)) == 1 passMatch := subtle.ConstantTimeCompare([]byte(pass), []byte(password)) == 1 if !userMatch || !passMatch { http.Error(w, "Forbidden", http.StatusForbidden) return } next(w, r) } } // JWTAuth wraps an HTTP handler with JWT bearer token auth. // This is a simple token comparison for HMAC-style tokens. func JWTAuth(token string, next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if token == "" { next(w, r) return } authHeader := r.Header.Get("Authorization") if authHeader == "" { http.Error(w, "Missing Authorization header", http.StatusUnauthorized) return } // Support both "Bearer " and "" directly provided := authHeader if len(authHeader) > 7 && authHeader[:7] == "Bearer " { provided = authHeader[7:] } if subtle.ConstantTimeCompare([]byte(provided), []byte(token)) != 1 { http.Error(w, "Forbidden", http.StatusForbidden) return } next(w, r) } }