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

webhook

package
v1.8.0 Latest Latest
Warning

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

Go to latest
Published: Sep 18, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package webhook verifies GitHub webhook deliveries.

GitHub signs each webhook delivery with HMAC-SHA256 over the raw request body using the secret configured on the webhook. This package verifies the X-Hub-Signature-256 header in constant time and exposes an http.Handler middleware for ergonomic integration.

See https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries.

Index

Examples

Constants

View Source
const (
	SignatureHeader = "X-Hub-Signature-256"
	EventHeader     = "X-GitHub-Event"
	DeliveryHeader  = "X-GitHub-Delivery"
)

Header names GitHub sets on every webhook delivery.

View Source
const DefaultMaxPayloadSize int64 = 25 * 1024 * 1024

DefaultMaxPayloadSize matches GitHub's documented 25 MiB delivery cap.

Variables

View Source
var (
	ErrMissingSecret          = errors.New("webhook: secret must not be empty")
	ErrMissingSignature       = errors.New("webhook: missing signature header")
	ErrInvalidSignatureFormat = errors.New("webhook: invalid signature format")
	ErrSignatureMismatch      = errors.New("webhook: signature mismatch")
)

Sentinel errors returned by Verify. Callers can branch with errors.Is.

Functions

func Middleware

func Middleware(secret []byte, opts ...MiddlewareOpt) func(http.Handler) http.Handler

Middleware returns net/http middleware that verifies the signature header against secret before invoking next. Failed verifications short-circuit with 401 Unauthorized; bodies larger than the configured cap return 413. The request body is restored for downstream handlers.

An empty secret rejects every delivery with ErrMissingSecret rather than verifying against a zero-length HMAC key, so a misconfigured deployment fails closed and surfaces as failed deliveries instead of accepting forgeries.

Example

Middleware verifies X-Hub-Signature-256 on every delivery and restores the request body before invoking the wrapped handler. Failed verifications short-circuit with 401; oversized bodies return 413.

package main

import (
	"log"
	"net/http"
	"os"

	"github.com/jferrl/go-githubauth/webhook"
)

func main() {
	secret := []byte(os.Getenv("GITHUB_WEBHOOK_SECRET"))

	mux := http.NewServeMux()
	mux.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
		// The body reaching this handler is already authenticated.
		event := r.Header.Get(webhook.EventHeader)
		delivery := r.Header.Get(webhook.DeliveryHeader)

		log.Printf("received %s delivery=%s", event, delivery)
		w.WriteHeader(http.StatusNoContent)
	})

	log.Fatal(http.ListenAndServe(":8080", webhook.Middleware(secret)(mux)))
}

func Verify

func Verify(secret, body []byte, signature string) error

Verify reports whether signature is a valid HMAC-SHA256 of body using secret. signature must be in GitHub's "sha256=<hex>" form, as delivered in the X-Hub-Signature-256 header. Comparison runs in constant time.

An empty secret returns ErrMissingSecret: HMAC would otherwise accept the zero-length key and treat forged deliveries as authentic.

Example

Verify checks a delivery outside net/http — AWS Lambda, Cloud Run event triggers, or messages consumed from a queue.

package main

import (
	"errors"
	"fmt"
	"os"

	"github.com/jferrl/go-githubauth/webhook"
)

func main() {
	secret := []byte(os.Getenv("GITHUB_WEBHOOK_SECRET"))
	body := []byte(`{"action":"opened"}`)
	signature := "sha256=..." // value of the X-Hub-Signature-256 header

	err := webhook.Verify(secret, body, signature)
	switch {
	case err == nil:
		// body is trusted from here
	case errors.Is(err, webhook.ErrMissingSignature):
		fmt.Println("header absent")
	case errors.Is(err, webhook.ErrInvalidSignatureFormat):
		fmt.Println("malformed header")
	case errors.Is(err, webhook.ErrSignatureMismatch):
		fmt.Println("wrong secret or tampered body")
	}
}

Types

type MiddlewareOpt

type MiddlewareOpt func(*middlewareConfig)

MiddlewareOpt configures Middleware.

func WithErrorHandler

func WithErrorHandler(fn func(http.ResponseWriter, *http.Request, error)) MiddlewareOpt

WithErrorHandler overrides how verification failures are reported. The default writes 401 Unauthorized (or 413 for oversized bodies) with a short plain-text reason.

func WithMaxPayloadSize

func WithMaxPayloadSize(n int64) MiddlewareOpt

WithMaxPayloadSize overrides the request body size cap. A non-positive value disables the cap, which is not recommended in production.

Jump to

Keyboard shortcuts

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