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

webhook

package
v0.0.13 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package webhook implements webhook signature verification for SDK consumers receiving FlowCatalyst webhooks.

The signing algorithm MUST match the router's sign_webhook in internal/router/mediator.go byte-for-byte. Both sides verify against a shared test vector in tests/golden/webhook/.

Index

Constants

View Source
const (
	ValidatorSignatureHeader = "X-FlowCatalyst-Signature"
	ValidatorTimestampHeader = "X-FlowCatalyst-Timestamp"
)

Header names accepted by the Validator. HTTP header lookups are case-insensitive, so these match the router's uppercase X-FLOWCATALYST-* headers in any compliant framework.

Both this Validator and Verifier expect the timestamp format the FlowCatalyst router actually emits: ISO8601 with millisecond precision (e.g. 2026-05-24T08:30:00.123Z). A bare Unix-seconds integer is also accepted for backward compatibility. The two types differ only in API style; prefer Verifier for new code.

View Source
const DefaultToleranceSecs = 300

DefaultToleranceSecs is how stale a timestamp may be before rejection.

View Source
const FutureGraceSecs = 60

FutureGraceSecs caps how far into the future a timestamp may be (clock skew between platform and consumer).

View Source
const SignatureHeader = "X-FLOWCATALYST-SIGNATURE"

SignatureHeader matches the router's outbound header name.

View Source
const TimestampHeader = "X-FLOWCATALYST-TIMESTAMP"

TimestampHeader matches the router's outbound header name.

Variables

View Source
var (
	ErrValidatorMissingSignature = errors.New("webhook: missing signature header (" + ValidatorSignatureHeader + ")")
	ErrValidatorMissingTimestamp = errors.New("webhook: missing timestamp header (" + ValidatorTimestampHeader + ")")
	ErrValidatorInvalidTimestamp = errors.New("webhook: invalid timestamp")
	ErrValidatorInvalidSignature = errors.New("webhook: invalid signature")
	ErrTimestampExpired          = errors.New("webhook: timestamp expired")
	ErrTimestampInFuture         = errors.New("webhook: timestamp is in the future")
	ErrMissingSecret             = errors.New("webhook: signing secret not configured")
)

Sentinel validation errors used by Validator. Use errors.Is to branch.

View Source
var (
	ErrMissingSignature = errors.New("webhook: missing signature header")
	ErrMissingTimestamp = errors.New("webhook: missing timestamp header")
	ErrBadTimestamp     = errors.New("webhook: malformed timestamp")
	ErrStaleTimestamp   = errors.New("webhook: timestamp outside clock skew tolerance")
	ErrBadSignature     = errors.New("webhook: signature does not match")
)

Errors.

Functions

This section is empty.

Types

type Validator

type Validator struct {
	// contains filtered or unexported fields
}

Validator validates HMAC-SHA256 webhook signatures. The signed message is timestamp || payload (hex-encoded). The timestamp is the ISO8601 millisecond value emitted by the FlowCatalyst router (a bare Unix-seconds integer is also accepted for backward compatibility).

Validator and Verifier are functionally equivalent; they differ only in API style. Prefer Verifier for new code.

func NewValidator

func NewValidator(secret string, opts ...ValidatorOption) *Validator

NewValidator builds a Validator with the given signing secret.

func ValidatorFromEnv

func ValidatorFromEnv(opts ...ValidatorOption) (*Validator, error)

ValidatorFromEnv builds a Validator from FLOWCATALYST_SIGNING_SECRET. Returns ErrMissingSecret if the env var is unset or empty.

func (*Validator) ComputeSignature

func (v *Validator) ComputeSignature(timestamp string, payload []byte) string

ComputeSignature renders the expected hex-encoded HMAC-SHA256 for a (timestamp, payload) pair. Exposed so consumers can sign outbound callbacks with the same algorithm.

func (*Validator) Validate

func (v *Validator) Validate(signature, timestamp string, payload []byte) error

Validate checks the signature against the body and timestamp.

  • signature: value of X-FlowCatalyst-Signature header (hex HMAC-SHA256)
  • timestamp: value of X-FlowCatalyst-Timestamp header (ISO8601 ms, e.g. 2026-05-24T08:30:00.123Z; a bare Unix-seconds integer is also accepted)
  • payload: raw request body

Returns nil on success, or one of the sentinel errors. The signature comparison is constant-time.

type ValidatorOption

type ValidatorOption func(*Validator)

ValidatorOption configures a Validator.

func WithClock

func WithClock(now func() time.Time) ValidatorOption

WithClock overrides the time source. Tests use this to inject a fixed clock.

func WithTolerance

func WithTolerance(d time.Duration) ValidatorOption

WithTolerance sets the timestamp freshness window. Default 300s.

type Verifier

type Verifier struct {

	// MaxClockSkew is how far the inbound timestamp may differ from now.
	// Defaults to 5 minutes to allow for clock drift between sender and receiver.
	MaxClockSkew time.Duration
	// contains filtered or unexported fields
}

Verifier validates inbound webhook signatures.

func NewVerifier

func NewVerifier(secret string) *Verifier

NewVerifier wires a verifier with the supplied signing secret.

func (*Verifier) Verify

func (v *Verifier) Verify(body []byte, signature, timestamp string) error

Verify validates the signature header against the supplied body.

`body` MUST be the raw bytes received over the wire (don't re-serialize — that would re-introduce JSON-library-dependent variation). `signature` is the hex from the X-FLOWCATALYST-SIGNATURE header. `timestamp` is the X-FLOWCATALYST-TIMESTAMP header.

Jump to

Keyboard shortcuts

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