SafeWebhook/ Guides
Launch Workbench
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.

Launch Webhook Workbench →

Explore Other Webhook Framework Guides