reqsign

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Mar 1, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package reqsign provides HMAC-SHA256 request signing and verification for service-to-service authentication and webhook delivery.

Signing model

The signed payload is:

<unix-timestamp-seconds>\n<request-body>

The HMAC-SHA256 of this payload (keyed with the shared secret) is transmitted in the request header as a hex string. The timestamp binds the signature to a specific point in time; the verifier rejects signatures outside a configurable replay window (default ±5 minutes).

This is the same scheme used by Stripe, GitHub, and Twilio webhooks.

Outbound (signing)

transport := reqsign.NewSigningTransport([]byte("shared-secret"), nil)
client := &http.Client{Transport: transport}
client.Post(url, "application/json", body)

Inbound (verification)

mux.Handle("/webhook", reqsign.Middleware([]byte("shared-secret"))(handler))

Index

Constants

View Source
const (
	// DefaultHeader is the request header carrying the signature.
	DefaultHeader = "X-Signature"
	// DefaultTimestampHeader carries the Unix timestamp used in the signature.
	DefaultTimestampHeader = "X-Timestamp"
	// DefaultReplayWindow is the maximum age of an accepted signature.
	DefaultReplayWindow = 5 * time.Minute
)

Variables

View Source
var ErrInvalidSignature = errors.New("reqsign: invalid signature")

ErrInvalidSignature is returned when a request signature does not match.

View Source
var ErrMissingHeader = errors.New("reqsign: missing signature header")

ErrMissingHeader is returned when the expected signature headers are absent.

View Source
var ErrReplayDetected = errors.New("reqsign: timestamp outside replay window")

ErrReplayDetected is returned when the request timestamp is outside the replay window, indicating a potential replay attack.

Functions

func Middleware

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

Middleware returns an HTTP middleware that verifies the HMAC-SHA256 signature on inbound requests (e.g. webhooks from a third-party service).

The request body is read, verified, and then restored so that downstream handlers can read it again.

func Sign

func Sign(secret, body []byte, timestamp time.Time) string

Sign computes an HMAC-SHA256 signature over "<timestamp>\n<body>" using the given secret. Returns the hex-encoded signature.

func Verify

func Verify(secret, body []byte, timestamp time.Time, sig string) bool

Verify checks whether sig is the correct HMAC-SHA256 signature of body at the given timestamp. Uses constant-time comparison to prevent timing attacks.

func VerifyRaw added in v1.0.1

func VerifyRaw(secret, body []byte, sig string) bool

VerifyRaw checks an HMAC-SHA256 signature over the raw body only, with no timestamp prefix. Use this for webhook providers that sign the body directly without a timestamp (e.g. Didit). Replay protection (timestamp window check) must be handled separately by the caller.

Uses constant-time comparison to prevent timing attacks.

ts, _ := strconv.ParseInt(r.Header.Get("X-Webhook-Timestamp"), 10, 64)
if math.Abs(float64(time.Now().Unix()-ts)) > 300 { /* reject */ }
ok := reqsign.VerifyRaw([]byte(secret), body, r.Header.Get("X-Webhook-Signature"))

Types

type SigningTransport

type SigningTransport struct {
	Secret          []byte
	Transport       http.RoundTripper
	Header          string
	TimestampHeader string
}

SigningTransport is an http.RoundTripper that automatically signs every outbound request with HMAC-SHA256 before sending it.

client := &http.Client{Transport: reqsign.NewSigningTransport(secret, nil)}

func NewSigningTransport

func NewSigningTransport(secret []byte, base http.RoundTripper) *SigningTransport

NewSigningTransport creates a SigningTransport with the given secret. base may be nil, in which case http.DefaultTransport is used.

func (*SigningTransport) RoundTrip

func (t *SigningTransport) RoundTrip(r *http.Request) (*http.Response, error)

RoundTrip signs the request and delegates to the underlying transport.

type VerifyOptions

type VerifyOptions struct {
	// Header is the request header carrying the hex signature.
	// Defaults to DefaultHeader ("X-Signature").
	Header string
	// TimestampHeader is the request header carrying the Unix timestamp.
	// Defaults to DefaultTimestampHeader ("X-Timestamp").
	TimestampHeader string
	// ReplayWindow is how far in the past or future a timestamp may be.
	// Defaults to DefaultReplayWindow (5 minutes).
	ReplayWindow time.Duration
	// OnError is called when verification fails. Defaults to a 401 JSON response.
	OnError func(w http.ResponseWriter, r *http.Request, err error)
}

VerifyOptions configures the inbound verification middleware.

Jump to

Keyboard shortcuts

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