Documentation
¶
Index ¶
- Constants
- Variables
- func ComputeDigest(data any) (string, error)
- func DeserializePaymentRequest(encoded string) (map[string]any, error)
- func IsExpired(expires string) bool
- func IsPaymentError(err error) bool
- func MarkUsed(ctx context.Context, store Store, key string) (bool, error)
- func MergeRequest(method ServerMethod, callSiteRequest map[string]any) map[string]any
- func MethodKey(m ServerMethod) string
- func SerializeChallenge(c Challenge) string
- func SerializeCredential(cred Credential) string
- func SerializePaymentRequest(req map[string]any) string
- func SerializeReceipt(r Receipt) string
- func VerifyChallenge(c Challenge, secretKey string) bool
- func VerifyDigest(digest string, data any) (bool, error)
- type Challenge
- type ChallengeParams
- type ClientMethod
- type Credential
- type MemoryStore
- type PaymentError
- func AsPaymentError(err error) (*PaymentError, bool)
- func ErrBadRequest(reason string) *PaymentError
- func ErrChannelClosed(reason string) *PaymentError
- func ErrChannelNotFound(reason string) *PaymentError
- func ErrInsufficientBalance(reason string) *PaymentError
- func ErrInvalidChallenge(id, reason string) *PaymentError
- func ErrInvalidPayload(reason string) *PaymentError
- func ErrInvalidSignature(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(description string) *PaymentError
- func ErrVerificationFailed(reason string) *PaymentError
- type ProblemDetails
- type Receipt
- type ReceiptParams
- type ServerMethod
- type Store
Constants ¶
const ( // HTTP header names. AuthorizationHeader = "Authorization" WWWAuthenticateHeader = "WWW-Authenticate" PaymentReceiptHeader = "Payment-Receipt" ContentTypeHeader = "Content-Type" CacheControlHeader = "Cache-Control" XForwardedHostHeader = "X-Forwarded-Host" IdempotencyKeyHeader = "Idempotency-Key" )
const ( // Shared HTTP header values and auth scheme fragments. AuthSchemePayment = "Payment" AuthSchemePaymentPrefix = AuthSchemePayment + " " CacheControlNoStore = "no-store" ReceiptStatusSuccess = "success" )
const ( // Common media types. MediaTypeJSON = "application/json" MediaTypeProblemJSON = "application/problem+json" MediaTypeFormURLEncoded = "application/x-www-form-urlencoded" HeaderValueBooleanTrue = "true" HeaderIdempotentReplayed = "idempotent-replayed" )
Variables ¶
var Expires = expiresHelper{}
Expires provides convenience functions for generating ISO 8601 expiration timestamps. Pass the result as the Expires field in ChallengeParams.
Example:
challenge, _ := mppx.NewChallenge(mppx.ChallengeParams{
SecretKey: secretKey,
Realm: "api.example.com",
Expires: mppx.Minutes(5),
// ...
})
Functions ¶
func ComputeDigest ¶
ComputeDigest computes a SHA-256 digest of the given data. The returned string is in the format "sha-256=<base64>", suitable for the digest field in a Challenge.
data may be a []byte, string, or a JSON-serializable value.
func DeserializePaymentRequest ¶
DeserializePaymentRequest decodes a base64url-encoded payment request string into a map.
func IsExpired ¶
IsExpired reports whether an ISO 8601 expiration timestamp has passed. Returns false if the timestamp is empty (no expiration).
func IsPaymentError ¶
IsPaymentError reports whether err is or wraps a *PaymentError.
func MarkUsed ¶
MarkUsed marks a key as used in the store (for replay detection). Returns (true, nil) if the key was newly marked, (false, nil) if already used.
func MergeRequest ¶
func MergeRequest(method ServerMethod, callSiteRequest map[string]any) map[string]any
MergeRequest merges method defaults with call-site request parameters. Call-site values take precedence over defaults.
func MethodKey ¶
func MethodKey(m ServerMethod) string
MethodKey returns the canonical "name/intent" key for a ServerMethod.
func SerializeChallenge ¶
SerializeChallenge serializes a Challenge to the WWW-Authenticate header value format.
Format: Payment id="...", realm="...", method="...", intent="...", request="<base64url>"[, ...]
func SerializeCredential ¶
func SerializeCredential(cred Credential) string
SerializeCredential serializes a Credential to the Authorization header value format.
Format: Payment <base64url(JSON)>
func SerializePaymentRequest ¶
SerializePaymentRequest serializes a payment request map to a base64url-encoded canonical JSON string. Go's encoding/json sorts map keys, producing deterministic output suitable for HMAC computation.
func SerializeReceipt ¶
SerializeReceipt serializes a Receipt to a base64url-encoded JSON string suitable for the Payment-Receipt response header.
func VerifyChallenge ¶
VerifyChallenge verifies that a challenge's ID matches the expected HMAC-SHA256. Uses constant-time comparison to prevent timing attacks.
Types ¶
type Challenge ¶
type Challenge struct {
// ID is the challenge identifier. When created with SecretKey it is HMAC-bound to its contents.
ID string `json:"id"`
// Realm identifies the server (e.g. hostname).
Realm string `json:"realm"`
// Method is the payment method name (e.g. "tempo", "stripe").
Method string `json:"method"`
// Intent is the intent type (e.g. "charge", "session").
Intent string `json:"intent"`
// Request contains method-specific payment parameters.
Request map[string]any `json:"request"`
// Digest is an optional SHA-256 digest of the HTTP request body ("sha-256=<base64>").
Digest string `json:"digest,omitempty"`
// Expires is an optional ISO 8601 expiration timestamp.
Expires string `json:"expires,omitempty"`
// Opaque contains optional server-defined correlation data. Clients MUST NOT modify this.
Opaque map[string]string `json:"opaque,omitempty"`
// Description is an optional human-readable payment description.
Description string `json:"description,omitempty"`
}
Challenge is a payment challenge issued by a server in a WWW-Authenticate header.
func DeserializeChallenge ¶
DeserializeChallenge parses the first Payment challenge from a WWW-Authenticate header value.
func DeserializeChallenges ¶
DeserializeChallenges parses all Payment challenges from a WWW-Authenticate header value that may contain multiple comma-separated challenges.
func NewChallenge ¶
func NewChallenge(p ChallengeParams) (Challenge, error)
NewChallenge creates a Challenge. Either ID or SecretKey must be set in params.
type ChallengeParams ¶
type ChallengeParams struct {
// ID is an explicit challenge identifier.
ID string
// SecretKey causes the ID to be computed as HMAC-SHA256 over the challenge parameters.
// Use this instead of ID for stateless server-side verification.
SecretKey string
// Realm identifies the server.
Realm string
// Method is the payment method name.
Method string
// Intent is the intent type.
Intent string
// Request contains method-specific payment parameters.
Request map[string]any
// Digest is an optional body digest.
Digest string
// Expires is an optional ISO 8601 expiration timestamp.
Expires string
// Opaque contains optional server-defined correlation data.
Opaque map[string]string
// Description is an optional human-readable description.
Description string
}
ChallengeParams holds parameters for creating a new Challenge. Either ID or SecretKey must be provided.
type ClientMethod ¶
type ClientMethod interface {
// Name returns the payment method identifier.
Name() string
// Intent returns the intent type.
Intent() string
// CreateCredential creates a payment credential from a challenge.
// Returns the serialized credential string suitable for an Authorization header.
CreateCredential(ctx context.Context, challenge Challenge) (string, error)
}
ClientMethod is a payment method that creates credentials on the client side. Implement this interface to add a custom payment method to your client.
type Credential ¶
type Credential struct {
// Challenge is the challenge this credential responds to.
Challenge Challenge `json:"challenge"`
// Payload contains method-specific payment proof (e.g. transaction hash, signature).
// The concrete type depends on the payment method.
Payload any `json:"payload"`
// Source is an optional payer identifier as a DID (e.g. "did:pkh:eip155:1:0x...").
Source string `json:"source,omitempty"`
}
Credential is a payment credential sent by a client in an Authorization header.
func DeserializeCredential ¶
func DeserializeCredential(header string) (Credential, error)
DeserializeCredential parses an Authorization header value into a Credential.
func ExtractCredential ¶
func ExtractCredential(r *http.Request) (Credential, bool, error)
ExtractCredential extracts a Credential from an HTTP request's Authorization header. Returns (cred, true, nil) if a valid Payment credential is present. Returns (Credential{}, false, nil) if no Payment scheme is present. Returns (Credential{}, true, err) if a Payment scheme is present but malformed.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is a thread-safe in-memory Store implementation. Suitable for development and testing; does not persist across restarts.
func NewMemoryStore ¶
func NewMemoryStore() *MemoryStore
NewMemoryStore creates a new in-memory store.
type PaymentError ¶
type PaymentError struct {
// ErrorType is the RFC 9457 problem type URI.
ErrorType string
// Title is a human-readable summary.
Title string
// HTTPStatus is the HTTP status code (default 402).
HTTPStatus int
// Detail is a human-readable explanation.
Detail string
}
PaymentError is the base type for all payment-related errors. It implements the error interface and serializes to RFC 9457 Problem Details.
func AsPaymentError ¶
func AsPaymentError(err error) (*PaymentError, bool)
AsPaymentError returns the *PaymentError within err, or (nil, false).
func ErrBadRequest ¶
func ErrBadRequest(reason string) *PaymentError
ErrBadRequest creates a "bad request" error (400).
func ErrChannelClosed ¶
func ErrChannelClosed(reason string) *PaymentError
ErrChannelClosed creates a "channel closed" error (410).
func ErrChannelNotFound ¶
func ErrChannelNotFound(reason string) *PaymentError
ErrChannelNotFound creates a "channel not found" error (410).
func ErrInsufficientBalance ¶
func ErrInsufficientBalance(reason string) *PaymentError
ErrInsufficientBalance creates an "insufficient balance" error (402) for streaming sessions.
func ErrInvalidChallenge ¶
func ErrInvalidChallenge(id, reason string) *PaymentError
ErrInvalidChallenge creates an "invalid challenge" error (402).
func ErrInvalidPayload ¶
func ErrInvalidPayload(reason string) *PaymentError
ErrInvalidPayload creates an "invalid payload" error (402).
func ErrInvalidSignature ¶
func ErrInvalidSignature(reason string) *PaymentError
ErrInvalidSignature creates an "invalid signature" error (402) for session vouchers.
func ErrMalformedCredential ¶
func ErrMalformedCredential(reason string) *PaymentError
ErrMalformedCredential creates a "malformed credential" error (402).
func ErrMethodUnsupported ¶
func ErrMethodUnsupported(method string) *PaymentError
ErrMethodUnsupported creates a "method unsupported" error (400).
func ErrPaymentExpired ¶
func ErrPaymentExpired(expires string) *PaymentError
ErrPaymentExpired creates a "payment expired" error (402).
func ErrPaymentInsufficient ¶
func ErrPaymentInsufficient(reason string) *PaymentError
ErrPaymentInsufficient creates a "payment insufficient" error (402).
func ErrPaymentRequired ¶
func ErrPaymentRequired(description string) *PaymentError
ErrPaymentRequired creates a "payment required" error (402).
func ErrVerificationFailed ¶
func ErrVerificationFailed(reason string) *PaymentError
ErrVerificationFailed creates a "verification failed" error (402).
func (*PaymentError) Error ¶
func (e *PaymentError) Error() string
func (*PaymentError) Status ¶
func (e *PaymentError) Status() int
Status returns the HTTP status code for this error (defaults to 402).
func (*PaymentError) ToProblemDetails ¶
func (e *PaymentError) ToProblemDetails(challengeID string) ProblemDetails
ToProblemDetails converts the error to RFC 9457 Problem Details format.
type ProblemDetails ¶
type ProblemDetails struct {
Type string `json:"type"`
Title string `json:"title"`
Status int `json:"status"`
Detail string `json:"detail"`
ChallengeID string `json:"challengeId,omitempty"`
}
ProblemDetails is an RFC 9457 Problem Details object returned in 402 response bodies.
type Receipt ¶
type Receipt struct {
// Method is the payment method used (e.g. "tempo", "stripe").
Method string `json:"method"`
// Reference is a method-specific payment reference (e.g. transaction hash).
Reference string `json:"reference"`
// Status is always "success". Failures use HTTP 402 + Problem Details.
Status string `json:"status"`
// Timestamp is the RFC 3339 settlement timestamp.
Timestamp string `json:"timestamp"`
// ExternalID is an optional external reference ID echoed from the credential payload.
ExternalID string `json:"externalId,omitempty"`
}
Receipt is a payment receipt returned by a server after successful payment verification.
func DeserializeReceipt ¶
DeserializeReceipt decodes a base64url-encoded Payment-Receipt header value.
func ExtractReceipt ¶
ExtractReceipt extracts the Receipt from an HTTP response's Payment-Receipt header.
func NewReceipt ¶
func NewReceipt(p ReceiptParams) Receipt
NewReceipt creates a Receipt. Status is always set to "success".
type ReceiptParams ¶
type ReceiptParams struct {
Method string
Reference string
Timestamp time.Time // defaults to time.Now() if zero
ExternalID string
}
ReceiptParams holds parameters for creating a Receipt.
type ServerMethod ¶
type ServerMethod interface {
// Name returns the payment method identifier (e.g. "tempo", "stripe").
Name() string
// Intent returns the intent type (e.g. "charge", "session").
Intent() string
// DefaultRequest returns default request parameters merged with call-site options.
// Return nil if no defaults.
DefaultRequest() map[string]any
// Verify verifies a payment credential and returns a Receipt.
// Return a *PaymentError for payment-specific failures (will be serialized to RFC 9457).
// Return any other error for internal failures (wrapped in VerificationFailedError).
Verify(ctx context.Context, cred Credential, req map[string]any) (Receipt, error)
}
ServerMethod is a payment method that verifies credentials on the server side. Implement this interface to add a custom payment method to your server.
Example usage:
type MyChargeMethod struct {
recipient string
currency string
}
func (m *MyChargeMethod) Name() string { return "mymethod" }
func (m *MyChargeMethod) Intent() string { return "charge" }
func (m *MyChargeMethod) DefaultRequest() map[string]any {
return map[string]any{"currency": m.currency, "recipient": m.recipient}
}
func (m *MyChargeMethod) Verify(ctx context.Context, cred Credential, req map[string]any) (Receipt, error) {
// verify payment on-chain, via API, etc.
return NewReceipt(ReceiptParams{Method: m.Name(), Reference: txHash}), nil
}
type Store ¶
type Store interface {
// Get retrieves a value by key. Returns ("", false, nil) if not found.
Get(ctx context.Context, key string) (string, bool, error)
// Put stores a value by key.
Put(ctx context.Context, key, value string) error
// Delete removes a value by key.
Delete(ctx context.Context, key string) error
}
Store is a generic key-value store interface for tracking used credentials, session state, and other payment-related state.
Implement this interface to use Redis, Postgres, Cloudflare KV, etc.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package client implements the Machine Payment Protocol client-side handler.
|
Package client implements the Machine Payment Protocol client-side handler. |
|
examples
|
|
|
basic/client
command
Example MPP client that automatically handles 402 Payment Required responses.
|
Example MPP client that automatically handles 402 Payment Required responses. |
|
basic/server
command
Example MPP server using net/http and Gin.
|
Example MPP server using net/http and Gin. |
|
fiber/client
command
Fiber MPP client — exercises the Fiber server example.
|
Fiber MPP client — exercises the Fiber server example. |
|
fiber/server
command
Fiber MPP server — payment-gated photo and generation API.
|
Fiber MPP server — payment-gated photo and generation API. |
|
gin-tempo/client
command
Gin + Tempo MPP client example.
|
Gin + Tempo MPP client example. |
|
gin-tempo/server
command
Gin + Tempo MPP server example.
|
Gin + Tempo MPP server example. |
|
http-middleware/client
command
net/http middleware patterns client — exercises all four server patterns.
|
net/http middleware patterns client — exercises all four server patterns. |
|
http-middleware/server
command
net/http middleware patterns server — four ways to gate routes with MPP payments.
|
net/http middleware patterns server — four ways to gate routes with MPP payments. |
|
multi-method/client
command
Multi-method MPP client — demonstrates client-side method selection with server.Compose.
|
Multi-method MPP client — demonstrates client-side method selection with server.Compose. |
|
multi-method/server
command
Multi-method MPP server — accepts two payment methods on the same route.
|
Multi-method MPP server — accepts two payment methods on the same route. |
|
session/client
command
Session MPP client example.
|
Session MPP client example. |
|
session/server
command
Session MPP server example.
|
Session MPP server example. |
|
stripe/client
command
Stripe MPP client — demonstrates the full 402 → SPT → payment flow.
|
Stripe MPP client — demonstrates the full 402 → SPT → payment flow. |
|
stripe/server
command
Stripe MPP server — fortune cookie API gated behind a $1.00 Stripe payment.
|
Stripe MPP server — fortune cookie API gated behind a $1.00 Stripe payment. |
|
tempo/charge/client
command
Tempo charge client example.
|
Tempo charge client example. |
|
tempo/charge/server
command
Tempo charge server example.
|
Tempo charge server example. |
|
tempo/session/client
command
Tempo session client example.
|
Tempo session client example. |
|
tempo/session/server
command
Tempo session server example.
|
Tempo session server example. |
|
middleware
|
|
|
fiber
Package fibermpp provides Fiber middleware for the Machine Payment Protocol.
|
Package fibermpp provides Fiber middleware for the Machine Payment Protocol. |
|
gin
Package ginmpp provides Gin middleware for the Machine Payment Protocol.
|
Package ginmpp provides Gin middleware for the Machine Payment Protocol. |
|
Package server implements the Machine Payment Protocol server-side handler.
|
Package server implements the Machine Payment Protocol server-side handler. |
|
Package stripe implements the Stripe payment method for the Machine Payment Protocol.
|
Package stripe implements the Stripe payment method for the Machine Payment Protocol. |
|
Package tempo implements Tempo payment methods for the Machine Payment Protocol.
|
Package tempo implements Tempo payment methods for the Machine Payment Protocol. |