Gin

Add Nyoxis threat detection to a Gin application using a middleware function and the standard net/http package.

Prerequisites

  • Go 1.21 or later
  • Gin v1.9 or later
  • A Nyoxis workspace API key — get one here

No extra install required

Uses the net/http and encoding/json packages from the Go standard library.

Middleware

Create middleware/nyoxis.go:

go
package middleware import ( "bytes" "context" "encoding/json" "fmt" "io" "log" "net/http" "time" "github.com/gin-gonic/gin" ) const nyoAPI = "https://api.nyoxis.com" type predictPayload struct { Method string `json:"method"` Path string `json:"path"` Query string `json:"query,omitempty"` Headers map[string]string `json:"headers,omitempty"` IPAddr string `json:"ip_addr,omitempty"` Body string `json:"body,omitempty"` } type predictResponse struct { IsCached bool `json:"is_cached"` Prediction *struct { Risk string `json:"risk"` RiskScore float64 `json:"risk_score"` Attacks []struct { Kind string `json:"kind"` Confidence float64 `json:"confidence"` } `json:"attacks"` } `json:"prediction"` } // NyoxisWAF returns a Gin middleware that calls /v0/predict for every request. // // Parameters: // // apiKey - your workspace API token (required) // blockOnHigh - if true, return 403 Forbidden when risk == "high" // failOpen - if true (default), pass request through on API failure func NyoxisWAF(apiKey string, blockOnHigh bool, failOpen bool) gin.HandlerFunc { if apiKey == "" { panic("nyoxis: apiKey is required") } client := &http.Client{Timeout: 3 * time.Second} return func(c *gin.Context) { // Read and restore the body var rawBody string if c.Request.Body != nil { bodyBytes, err := io.ReadAll(io.LimitReader(c.Request.Body, 1<<20 /* 1 MiB */)) if err == nil { rawBody = string(bodyBytes) c.Request.Body = io.NopCloser(bytes.NewReader(bodyBytes)) } } headers := make(map[string]string, len(c.Request.Header)) for k, vals := range c.Request.Header { if len(vals) > 0 { headers[k] = vals[0] } } payload := predictPayload{ Method: c.Request.Method, Path: c.Request.URL.Path, Query: c.Request.URL.RawQuery, Headers: headers, IPAddr: c.ClientIP(), Body: rawBody, } body, _ := json.Marshal(payload) url := fmt.Sprintf("%s/v0/predict?api_key=%s", nyoAPI, apiKey) ctx, cancel := context.WithTimeout(c.Request.Context(), 3*time.Second) defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body)) if err != nil { log.Printf("[nyoxis] build request error: %v", err) goto passthrough } req.Header.Set("Content-Type", "application/json") { resp, err := client.Do(req) if err != nil { log.Printf("[nyoxis] prediction error: %v", err) goto passthrough } defer resp.Body.Close() var verdict predictResponse if err := json.NewDecoder(resp.Body).Decode(&verdict); err == nil { // Store verdict in Gin context c.Set("nyoxis", verdict) if blockOnHigh && verdict.Prediction != nil && verdict.Prediction.Risk == "high" { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "Forbidden"}) return } } } passthrough: if !failOpen { c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"error": "Service unavailable"}) return } c.Next() } }

Register the middleware

go
// main.go package main import ( "net/http" "os" "github.com/gin-gonic/gin" "yourmodule/middleware" ) func main() { r := gin.Default() // Apply globally r.Use(middleware.NyoxisWAF( os.Getenv("NYOXIS_API_KEY"), true, // blockOnHigh true, // failOpen )) r.GET("/", func(c *gin.Context) { risk := "unknown" if v, ok := c.Get("nyoxis"); ok { if verdict, ok := v.(middleware.PredictResponse); ok && verdict.Prediction != nil { risk = verdict.Prediction.Risk } } c.JSON(http.StatusOK, gin.H{"ok": true, "risk": risk}) }) r.Run(":8080") }

Acting on the verdict

go
r.GET("/sensitive", func(c *gin.Context) { if v, exists := c.Get("nyoxis"); exists { if verdict, ok := v.(middleware.PredictResponse); ok && verdict.Prediction != nil { p := verdict.Prediction if p.Risk == "high" || p.Risk == "medium" { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "Forbidden"}) return } for _, attack := range p.Attacks { if attack.Kind == "sql_injection" && attack.Confidence > 0.8 { // Log — could be a false positive; consider alerting first c.Set("security_alert", attack) } } } } c.JSON(http.StatusOK, gin.H{"data": "sensitive content"}) })

Next steps

  • API Reference — complete field descriptions and status codes.
  • Overview — how the classifier and redaction pipeline work.

Cookie preferences

Nyoxis uses essential cookies for authentication and session security. We only enable Analytics after you consent. See our Cookie Policy for details.