Go (Gin Framework)Go (Golang)
Go Gin Webhook Guide: c.GetRawData() & crypto/hmac Verification
Learn how to build high-performance webhook handlers in Golang with Gin framework. Read raw payload bytes with `c.GetRawData()` and verify HMAC signatures.
Direct Answer / Quick Implementation Guide
In Go Gin, read raw bytes using `c.GetRawData()` before binding JSON models. Compute HMAC digests with standard library `crypto/hmac` and `crypto/sha256`, and verify with `hmac.Equal()`.
Essential Implementation Takeaways
- •Use `c.GetRawData()` to retrieve raw request bytes.
- •Use `hmac.Equal(macA, macB)` for constant-time cryptographic verification.
- •Unmarshal JSON into Go structs after successful validation.
- •Acknowledge with `c.JSON(http.StatusOK, gin.H{"status": "ok"})`.
Common Gotchas in Go (Gin Framework) & How to Fix Them
Calling `c.ShouldBindJSON()` before getting raw bytes
Fix:Call `body, err := c.GetRawData()` first, verify, then `json.Unmarshal(body, &payload)`.
Complete Production Boilerplate
Go (Golang)// main.go (Go Gin Webhook Receiver)
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"net/http"
"github.com/gin-gonic/gin"
)
var webhookSecret = []byte("your_webhook_secret")
func WebhookHandler(c *gin.Context) {
// 1. Get raw request bytes
rawData, err := c.GetRawData()
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to read request body"})
return
}
// 2. Extract signature header
sigHeader := c.GetHeader("X-Hub-Signature-256")
if sigHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing signature header"})
return
}
// 3. Verify HMAC-SHA256
mac := hmac.New(sha256.New, webhookSecret)
mac.Write(rawData)
expectedMAC := "sha256=" + hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(sigHeader), []byte(expectedMAC)) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid signature"})
return
}
// 4. Unmarshal JSON safely
var event map[string]interface{}
if err := json.Unmarshal(rawData, &event); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON format"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "success"})
}
func main() {
r := gin.Default()
r.POST("/api/webhook", WebhookHandler)
r.Run(":8080")
}Step-by-Step Setup Guide
1
Call `rawData, err := c.GetRawData()` in your Gin handler.
2
Compute HMAC using `crypto/hmac` and `crypto/sha256`.
3
Verify with `hmac.Equal()`.
4
Decode payload into a Go struct with `json.Unmarshal()`.
5
Return `c.JSON(http.StatusOK, ...)`.
How to Test Locally on Your Machine
- Run `go run main.go` (running on :8080).
- Use SafeWebhook Replay Drawer to send test payloads to `http://localhost:8080/api/webhook`.
Frequently Asked Questions: Go (Gin Framework) Webhooks
Why use hmac.Equal() instead of == in Go?
`hmac.Equal()` performs a constant-time comparison, preventing timing side-channel attacks when validating signatures.
Test Your Go (Gin Framework) Webhook Handler Live
Capture payloads, simulate errors, and replay directly to your localhost server.