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 ¶
- Variables
- func B64Decode(s string) (map[string]any, error)
- func ConstantTimeEqual(a, b string) bool
- func ExtractAuthorizationScheme(header, scheme string) string
- func FindPaymentAuthorization(header string) string
- func FormatAuthenticate(c *Challenge, realm string) string
- func FormatAuthorization(c *Credential) string
- func FormatPaymentReceipt(r *Receipt) string
- func FormatReceipt(r *Receipt) string
- func GenerateChallengeID(opts GenerateChallengeIDInput) string
- func JSONEqual(left, right any) bool
- func ParseUnits(value string, decimals int) (int64, error)
- func SplitAuthenticate(header string) []string
- func TransformUnits(request map[string]any) (map[string]any, error)
- type Challenge
- func (c Challenge) MarshalJSON() ([]byte, error)
- func (c *Challenge) NewCredential(payload map[string]any, opts ...CredentialOption) *Credential
- func (c *Challenge) ToAuthenticate(realm string) string
- func (c *Challenge) ToEcho() ChallengeEcho
- func (c *Challenge) UnmarshalJSON(data []byte) error
- func (c *Challenge) Verify(secretKey, realm string) bool
- type ChallengeEcho
- type ChallengeOption
- type Credential
- type CredentialOption
- type ErrorType
- type GenerateChallengeIDInput
- type PaymentError
- func ErrBadRequest(reason string) *PaymentError
- func ErrInvalidChallenge(challengeID, reason string) *PaymentError
- func ErrInvalidPayload(reason string) *PaymentError
- func ErrMalformedCredential(reason string) *PaymentError
- func ErrMethodUnsupported(method string) *PaymentError
- func ErrPaymentExpired(expires string) *PaymentError
- func ErrPaymentInsufficient(reason string) *PaymentError
- func ErrPaymentRequired(realm, description string) *PaymentError
- func ErrVerificationFailed(reason string) *PaymentError
- type Receipt
- type ReceiptOption
Constants ¶
This section is empty.
Variables ¶
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.
var ErrVerification = errors.New("payment verification failed")
ErrVerification is a sentinel error for payment verification failures.
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 ConstantTimeEqual ¶
ConstantTimeEqual returns true if a and b are equal, using constant-time comparison to avoid timing side-channels.
func ExtractAuthorizationScheme ¶
ExtractAuthorizationScheme returns the first authorization value that matches the requested scheme from a possibly merged Authorization header.
func FindPaymentAuthorization ¶
FindPaymentAuthorization returns the Payment credential from an Authorization header. It tolerates comma-separated schemes and ignores non-Payment values.
func FormatAuthenticate ¶
FormatAuthenticate formats a Challenge as an authentication header value.
Output format: Payment id="...", realm="...", method="...", intent="...", request="..."
func FormatAuthorization ¶
func FormatAuthorization(c *Credential) string
FormatAuthorization formats a Credential as an Authorization header value.
Output format: Payment <base64url-json>
func FormatPaymentReceipt ¶
FormatPaymentReceipt formats a Receipt as a Payment-Receipt header value.
Output format: <base64url-json>
func FormatReceipt ¶
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 ParseUnits ¶
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 ¶
SplitAuthenticate splits a potentially merged authentication header value into individual scheme values while preserving commas inside quoted auth-param values.
func TransformUnits ¶
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 ¶
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 ¶
ParseChallenge parses a Payment challenge from a WWW-Authenticate header value.
func (Challenge) MarshalJSON ¶
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 ¶
ToAuthenticate formats this Challenge as an authentication header value.
func (*Challenge) ToEcho ¶
func (c *Challenge) ToEcho() ChallengeEcho
ToEcho returns the ChallengeEcho representation suitable for inclusion in a Credential.
func (*Challenge) UnmarshalJSON ¶
UnmarshalJSON accepts the standard JSON challenge shape and computes the cached RequestB64 field used by header serialization.
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://mpp.dev/errors/payment-required" ErrorTypeMalformedCredential ErrorType = "https://mpp.dev/errors/malformed-credential" ErrorTypeInvalidChallenge ErrorType = "https://mpp.dev/errors/invalid-challenge" ErrorTypeVerificationFailed ErrorType = "https://mpp.dev/errors/verification-failed" ErrorTypePaymentExpired ErrorType = "https://mpp.dev/errors/payment-expired" ErrorTypeInvalidPayload ErrorType = "https://mpp.dev/errors/invalid-payload" ErrorTypeBadRequest ErrorType = "https://mpp.dev/errors/bad-request" ErrorTypePaymentInsufficient ErrorType = "https://mpp.dev/errors/payment-insufficient" ErrorTypeMethodUnsupported ErrorType = "https://mpp.dev/errors/method-unsupported" )
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 400 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 400 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 ¶
FromPaymentReceipt parses a Payment-Receipt header value into a Receipt.
func ParsePaymentReceipt ¶
ParsePaymentReceipt parses a Payment-Receipt header value into a Receipt.
Expected format: <base64url-json>
func ParseReceipt ¶
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 ¶
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.