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

mpp

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2026 License: MIT, Apache-2.0, MIT Imports: 13 Imported by: 1

Documentation

Overview

Package mpp implements the Machine Payments Protocol (MPP) types and header serialization for Go. It provides Challenge, Credential, and Receipt types along with authentication and receipt header parsing and formatting helpers.

Index

Constants

This section is empty.

Variables

View Source
var BodyDigest = struct {
	Compute func(body any) string
	Verify  func(digest string, body any) bool
}{
	Compute: computeDigest,
	Verify:  verifyDigest,
}

BodyDigest provides helpers for computing and verifying SHA-256 digests. Compute returns a digest string in the form "sha-256=<base64>". Verify recomputes the digest and compares using constant-time comparison.

View Source
var ErrVerification = errors.New("payment verification failed")

ErrVerification is a sentinel error for payment verification failures.

View Source
var Expires = struct {
	Seconds func(n int) string
	Minutes func(n int) string
	Hours   func(n int) string
	Days    func(n int) string
	Weeks   func(n int) string
}{
	Seconds: func(n int) string { return formatISO(time.Now().UTC().Add(time.Duration(n) * time.Second)) },
	Minutes: func(n int) string { return formatISO(time.Now().UTC().Add(time.Duration(n) * time.Minute)) },
	Hours:   func(n int) string { return formatISO(time.Now().UTC().Add(time.Duration(n) * time.Hour)) },
	Days:    func(n int) string { return formatISO(time.Now().UTC().Add(time.Duration(n) * 24 * time.Hour)) },
	Weeks:   func(n int) string { return formatISO(time.Now().UTC().Add(time.Duration(n) * 7 * 24 * time.Hour)) },
}

Expires provides helpers for generating ISO 8601 expiration timestamps with millisecond precision and Z suffix.

Functions

func B64Decode

func B64Decode(s string) (map[string]any, error)

B64Decode decodes a base64url (no padding) string into a map.

func ConstantTimeEqual

func ConstantTimeEqual(a, b string) bool

ConstantTimeEqual returns true if a and b are equal, using constant-time comparison to avoid timing side-channels.

func ExtractAuthorizationScheme

func ExtractAuthorizationScheme(header, scheme string) string

ExtractAuthorizationScheme returns the first authorization value that matches the requested scheme from a possibly merged Authorization header.

func ExtractAuthorizationSchemeStrict added in v0.2.0

func ExtractAuthorizationSchemeStrict(header, scheme string) (string, error)

ExtractAuthorizationSchemeStrict returns a single authorization value that matches scheme, or an error if the header includes multiple matching values.

func FindPaymentAuthorization

func FindPaymentAuthorization(header string) string

FindPaymentAuthorization returns the Payment credential from an Authorization header. It tolerates comma-separated schemes and ignores non-Payment values.

func FindPaymentAuthorizationStrict added in v0.2.0

func FindPaymentAuthorizationStrict(header string) (string, error)

FindPaymentAuthorizationStrict returns the Payment credential from an Authorization header, or an error if more than one Payment credential exists.

func FormatAuthenticate

func FormatAuthenticate(c *Challenge, realm string) string

FormatAuthenticate formats a Challenge as an authentication header value.

Output format: Payment id="...", realm="...", method="...", intent="...", request="..."

func FormatAuthenticateStrict added in v0.1.2

func FormatAuthenticateStrict(c *Challenge, realm string) (string, error)

FormatAuthenticateStrict formats a Challenge as an authentication header value and rejects values that cannot be safely represented in quoted auth-params.

func FormatAuthorization

func FormatAuthorization(c *Credential) string

FormatAuthorization formats a Credential as an Authorization header value.

Output format: Payment <base64url-json>

func FormatPaymentReceipt

func FormatPaymentReceipt(r *Receipt) string

FormatPaymentReceipt formats a Receipt as a Payment-Receipt header value.

Output format: <base64url-json>

func FormatReceipt

func FormatReceipt(r *Receipt) string

FormatReceipt formats a Receipt as a receipt header value.

func GenerateChallengeID

func GenerateChallengeID(opts GenerateChallengeIDInput) string

GenerateChallengeID produces an HMAC-SHA256 challenge ID from the given inputs. The HMAC is computed over pipe-delimited fields:

realm|method|intent|request_b64|expires|digest|opaque_b64

The result is base64url-encoded without padding.

func JSONEqual

func JSONEqual(left, right any) bool

JSONEqual compares two JSON-like values using Go's stable JSON encoding.

func ParseUnits

func ParseUnits(value string, decimals int) (int64, error)

ParseUnits converts a human-readable decimal string to base units. For example, ParseUnits("1.5", 6) returns 1500000. Returns an error if value is not a valid decimal, is negative, or would produce fractional base units.

func SplitAuthenticate

func SplitAuthenticate(header string) []string

SplitAuthenticate splits a potentially merged authentication header value into individual scheme values while preserving commas inside quoted auth-param values.

func TransformUnits

func TransformUnits(request map[string]any) (map[string]any, error)

TransformUnits transforms request amounts from human-readable to base units. If a "decimals" key is present in the request map, it converts the "amount" field (and optionally "suggestedDeposit") from human-readable decimal strings to base unit strings, then removes the "decimals" key. If no "decimals" key is present, the request is returned unchanged.

Types

type Challenge

type Challenge struct {
	ID          string            `json:"id"`
	Method      string            `json:"method"`
	Intent      string            `json:"intent"`
	Request     map[string]any    `json:"request,omitempty"`
	Realm       string            `json:"realm,omitempty"`
	RequestB64  string            `json:"requestB64,omitempty"`
	Digest      string            `json:"digest,omitempty"`
	Expires     string            `json:"expires,omitempty"`
	Description string            `json:"description,omitempty"`
	Opaque      map[string]string `json:"opaque,omitempty"`
}

Challenge represents a server-issued payment challenge sent via the WWW-Authenticate header.

func FromAuthenticate

func FromAuthenticate(header string) (*Challenge, error)

FromAuthenticate parses an authentication header value into a Challenge.

func NewChallenge

func NewChallenge(secretKey, realm, method, intent string, request map[string]any, opts ...ChallengeOption) *Challenge

NewChallenge creates a new Challenge with an HMAC-bound ID. The secretKey and realm are used to compute the ID via GenerateChallengeID.

func ParseChallenge

func ParseChallenge(header string) (*Challenge, error)

ParseChallenge parses a Payment challenge from a WWW-Authenticate header value.

func (Challenge) MarshalJSON

func (c Challenge) MarshalJSON() ([]byte, error)

MarshalJSON emits the standard JSON challenge shape with a decoded request object, while keeping RequestB64 as an internal cache for header formatting.

func (*Challenge) NewCredential

func (c *Challenge) NewCredential(payload map[string]any, opts ...CredentialOption) *Credential

NewCredential builds a Credential from a Challenge and payment payload.

func (*Challenge) ToAuthenticate

func (c *Challenge) ToAuthenticate(realm string) string

ToAuthenticate formats this Challenge as an authentication header value.

func (*Challenge) ToAuthenticateStrict added in v0.1.2

func (c *Challenge) ToAuthenticateStrict(realm string) (string, error)

ToAuthenticateStrict formats this Challenge as an authentication header value and rejects values that cannot be safely represented in quoted auth-params.

func (*Challenge) ToEcho

func (c *Challenge) ToEcho() ChallengeEcho

ToEcho returns the ChallengeEcho representation suitable for inclusion in a Credential.

func (*Challenge) UnmarshalJSON

func (c *Challenge) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts the standard JSON challenge shape and computes the cached RequestB64 field used by header serialization.

func (*Challenge) Verify

func (c *Challenge) Verify(secretKey, realm string) bool

Verify checks whether the challenge ID matches the expected HMAC for the given secretKey and realm. Uses constant-time comparison.

type ChallengeEcho

type ChallengeEcho struct {
	ID      string            `json:"id"`
	Realm   string            `json:"realm,omitempty"`
	Method  string            `json:"method"`
	Intent  string            `json:"intent"`
	Request string            `json:"request,omitempty"`
	Expires string            `json:"expires,omitempty"`
	Digest  string            `json:"digest,omitempty"`
	Opaque  map[string]string `json:"opaque,omitempty"`
}

ChallengeEcho is the subset of a Challenge echoed back in a Credential.

type ChallengeOption

type ChallengeOption func(*challengeConfig)

ChallengeOption configures optional fields when creating a new Challenge.

func WithDescription

func WithDescription(desc string) ChallengeOption

WithDescription sets the human-readable description on a Challenge.

func WithDigest

func WithDigest(digest string) ChallengeOption

WithDigest sets the body digest on a Challenge.

func WithExpires

func WithExpires(expires string) ChallengeOption

WithExpires sets the expiration timestamp on a Challenge.

func WithMeta

func WithMeta(meta map[string]string) ChallengeOption

WithMeta sets opaque metadata key-value pairs on a Challenge.

type Credential

type Credential struct {
	Challenge ChallengeEcho  `json:"challenge"`
	Payload   map[string]any `json:"payload,omitempty"`
	Source    string         `json:"source,omitempty"`
}

Credential represents a client-submitted payment credential sent via the Authorization header.

func FromAuthorization

func FromAuthorization(header string) (*Credential, error)

FromAuthorization parses an Authorization header value into a Credential.

func ParseCredential

func ParseCredential(header string) (*Credential, error)

ParseCredential parses a Payment credential from an Authorization header value.

Expected format: Payment <base64url-json> The JSON payload contains: challenge (echo), payload, and optional source.

func (Credential) MarshalJSON

func (c Credential) MarshalJSON() ([]byte, error)

MarshalJSON emits the ergonomic JSON credential shape with a decoded challenge request object instead of the internal base64url string.

func (*Credential) ToAuthorization

func (c *Credential) ToAuthorization() string

ToAuthorization formats this Credential as an Authorization header value.

func (*Credential) UnmarshalJSON

func (c *Credential) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts a credential with either an object request or the raw base64url echo string and normalizes it into the wire-centric ChallengeEcho.

type CredentialOption

type CredentialOption func(*Credential)

CredentialOption configures optional fields when creating a Credential.

func WithCredentialSource

func WithCredentialSource(source string) CredentialOption

WithCredentialSource sets the optional payer identity on a Credential.

type ErrorType

type ErrorType string

ErrorType identifies a machine-readable MPP problem type.

const (
	ErrorTypePaymentRequired     ErrorType = "https://paymentauth.org/problems/payment-required"
	ErrorTypeMalformedCredential ErrorType = "https://paymentauth.org/problems/malformed-credential"
	ErrorTypeInvalidChallenge    ErrorType = "https://paymentauth.org/problems/invalid-challenge"
	ErrorTypeVerificationFailed  ErrorType = "https://paymentauth.org/problems/verification-failed"
	ErrorTypePaymentExpired      ErrorType = "https://paymentauth.org/problems/payment-expired"
	ErrorTypeInvalidPayload      ErrorType = "https://mpp.dev/errors/invalid-payload"
	ErrorTypeBadRequest          ErrorType = "https://mpp.dev/errors/bad-request"
	ErrorTypePaymentInsufficient ErrorType = "https://paymentauth.org/problems/payment-insufficient"
	ErrorTypeMethodUnsupported   ErrorType = "https://paymentauth.org/problems/method-unsupported"
)

func (ErrorType) Status

func (t ErrorType) Status() int

Status returns the default HTTP status for the error type.

func (ErrorType) Title

func (t ErrorType) Title() string

Title returns the default RFC 9457 title for the error type.

type GenerateChallengeIDInput

type GenerateChallengeIDInput struct {
	SecretKey string
	Realm     string
	Method    string
	Intent    string
	Request   map[string]any
	Expires   string
	Digest    string
	Opaque    map[string]string
}

GenerateChallengeIDInput holds the inputs for HMAC-based challenge ID generation.

type PaymentError

type PaymentError struct {
	Type   ErrorType `json:"type"`
	Title  string    `json:"title"`
	Status int       `json:"status"`
	Detail string    `json:"detail"`
}

PaymentError represents an MPP error using RFC 9457 Problem Details.

func ErrBadRequest

func ErrBadRequest(reason string) *PaymentError

ErrBadRequest returns a generic 400 error.

func ErrInvalidChallenge

func ErrInvalidChallenge(challengeID, reason string) *PaymentError

ErrInvalidChallenge returns a 402 error for invalid or tampered challenges.

func ErrInvalidPayload

func ErrInvalidPayload(reason string) *PaymentError

ErrInvalidPayload returns a 400 error for invalid payment payloads.

func ErrMalformedCredential

func ErrMalformedCredential(reason string) *PaymentError

ErrMalformedCredential returns a 402 error for unparseable credentials.

func ErrMethodUnsupported

func ErrMethodUnsupported(method string) *PaymentError

ErrMethodUnsupported returns a 400 error for unsupported payment methods.

func ErrPaymentExpired

func ErrPaymentExpired(expires string) *PaymentError

ErrPaymentExpired returns a 402 error for expired payment challenges.

func ErrPaymentInsufficient

func ErrPaymentInsufficient(reason string) *PaymentError

ErrPaymentInsufficient returns a 402 error for insufficient payment amounts.

func ErrPaymentRequired

func ErrPaymentRequired(realm, description string) *PaymentError

ErrPaymentRequired returns a 402 Payment Required error.

func ErrVerificationFailed

func ErrVerificationFailed(reason string) *PaymentError

ErrVerificationFailed returns a 402 error for failed payment verification.

func (*PaymentError) Error

func (e *PaymentError) Error() string

func (*PaymentError) ProblemDetails

func (e *PaymentError) ProblemDetails(challengeID string) map[string]any

ProblemDetails returns an RFC 9457 problem details map, optionally including a challengeID if non-empty.

func (*PaymentError) Unwrap

func (e *PaymentError) Unwrap() error

Unwrap lets errors.Is match against ErrVerification for verification errors.

type Receipt

type Receipt struct {
	Status     string         `json:"status"`
	Timestamp  time.Time      `json:"timestamp"`
	Reference  string         `json:"reference"`
	Method     string         `json:"method,omitempty"`
	ExternalID string         `json:"externalId,omitempty"`
	Extra      map[string]any `json:"extra,omitempty"`
}

Receipt represents a server-issued payment receipt sent via the Payment-Receipt header.

func FromPaymentReceipt

func FromPaymentReceipt(header string) (*Receipt, error)

FromPaymentReceipt parses a Payment-Receipt header value into a Receipt.

func ParsePaymentReceipt

func ParsePaymentReceipt(header string) (*Receipt, error)

ParsePaymentReceipt parses a Payment-Receipt header value into a Receipt.

Expected format: <base64url-json>

func ParseReceipt

func ParseReceipt(header string) (*Receipt, error)

ParseReceipt parses a receipt header value into a Receipt.

func Success

func Success(reference string, opts ...ReceiptOption) *Receipt

Success creates a new successful Receipt with the given reference and options.

func (*Receipt) ToPaymentReceipt

func (r *Receipt) ToPaymentReceipt() string

ToPaymentReceipt formats this Receipt as a Payment-Receipt header value.

type ReceiptOption

type ReceiptOption func(*Receipt)

ReceiptOption configures optional fields when creating a Receipt.

func WithExternalID

func WithExternalID(id string) ReceiptOption

WithExternalID sets the external transaction ID on a Receipt.

func WithExtra

func WithExtra(extra map[string]any) ReceiptOption

WithExtra sets extra metadata on a Receipt.

func WithReceiptMethod

func WithReceiptMethod(method string) ReceiptOption

WithReceiptMethod sets the payment method on a Receipt.

Jump to

Keyboard shortcuts

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