webhook

package
v0.0.9 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 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