server

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: 12 Imported by: 0

Documentation

Overview

Package server provides the generic challenge-or-verify flow for Payment authentication on the server side.

Examples import this package by its bare name. The Tempo charge package uses the alias `charge`, so there is no conflict.

Package server provides the server-side MPP payment handler.

It implements the HTTP 402 challenge/credential flow: when a request arrives without payment credentials, it returns a 402 with a WWW-Authenticate challenge. When valid credentials are provided, it verifies them and returns a receipt.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ChargeMiddleware

func ChargeMiddleware(m *Mpp, params ChargeParams) func(http.Handler) http.Handler

ChargeMiddleware creates an http.Handler middleware for the charge intent.

It calls Mpp.Charge with the provided ChargeParams, injects the incoming Authorization header automatically, returns a 402 challenge when payment is required, and stores the verified Credential and Receipt in the request context on success.

func ComposeMiddleware

func ComposeMiddleware(configs ...ComposeConfig) func(http.Handler) http.Handler

ComposeMiddleware creates an http.Handler middleware that supports multiple payment methods on a single route.

When no credential is present, it fans out to every configured method and returns a merged 402 response with one WWW-Authenticate header per method. When a credential is present, it dispatches to the matching method by comparing the credential's echoed method, intent, and canonical request.

All configs must share the same realm. ComposeMiddleware panics if configs is empty, any Mpp is nil, or realms differ.

func ContextWithPayment

func ContextWithPayment(ctx context.Context, credential *mpp.Credential, receipt *mpp.Receipt) context.Context

ContextWithPayment stores the verified payment objects on a request context.

func CredentialFromContext

func CredentialFromContext(ctx context.Context) *mpp.Credential

CredentialFromContext extracts the Credential from the request context.

func DetectRealm

func DetectRealm() string

DetectRealm auto-detects the server realm from environment variables. It checks MPP_REALM, FLY_APP_NAME, HEROKU_APP_NAME, RAILWAY_PUBLIC_DOMAIN, RENDER_EXTERNAL_HOSTNAME, VERCEL_URL, WEBSITE_HOSTNAME, HOST, and HOSTNAME in that order. Returns "MPP Payment" if none are set.

func DetectSecretKey

func DetectSecretKey() (string, error)

DetectSecretKey reads the MPP_SECRET_KEY environment variable. Returns an error if it is not set.

func ReadRequestBody added in v0.2.0

func ReadRequestBody(r *http.Request) ([]byte, error)

ReadRequestBody reads and restores r.Body so middleware can verify body digests without consuming the body before the protected handler runs.

func ReceiptFromContext

func ReceiptFromContext(ctx context.Context) *mpp.Receipt

ReceiptFromContext extracts the Receipt from the request context.

func ScopeFromHTTPRequest added in v0.2.0

func ScopeFromHTTPRequest(r *http.Request, route string) map[string]string

ScopeFromHTTPRequest returns the framework scope bound into charge requests.

func WriteChallenge

func WriteChallenge(w http.ResponseWriter, challenge *mpp.Challenge, realm string)

WriteChallenge serializes a 402 challenge response using RFC 9457 problem details.

func WritePaymentError

func WritePaymentError(w http.ResponseWriter, err error)

WritePaymentError serializes MPP verification errors as problem details.

Types

type ChargeParams

type ChargeParams struct {
	// Authorization is the incoming Authorization header value.
	Authorization string
	// Amount is the human-readable charge amount.
	Amount string
	// Currency overrides the method's default currency.
	Currency string
	// Recipient overrides the method's default recipient.
	Recipient string
	// ExternalID is copied into the request and echoed back in the Receipt.
	ExternalID string
	// Body is the actual request body to bind via the challenge digest.
	Body any
	// Expires overrides the default Challenge expiry.
	Expires string
	// Description is exposed in the server-generated Challenge.
	Description string
	// Memo sets a Tempo transfer memo when the method supports it.
	Memo string
	// Splits adds Tempo split-payment transfers under methodDetails.splits.
	Splits []tempo.SplitParams
	// FeePayer requests the sponsored Tempo flow when the method supports it.
	FeePayer bool
	// FeePayerURL points at a remote fee-payer signer.
	FeePayerURL string
	// SupportedModes advertises the Tempo submission modes allowed for this challenge.
	SupportedModes []tempo.ChargeMode
	// ChainID overrides the method's default Tempo chain ID.
	ChainID int
	// Meta stores opaque Challenge metadata.
	Meta map[string]string
	// MppxScope binds framework route/resource/query context into the request.
	MppxScope map[string]string
}

ChargeParams contains the parameters for a charge operation.

type ChargeRequestBuilder

type ChargeRequestBuilder interface {
	BuildChargeRequest(params ChargeParams) (map[string]any, error)
}

ChargeRequestBuilder lets a method provide a canonical request shape for the generic charge helper. Tempo uses this to normalize human amounts and nest method-specific fields under methodDetails.

type ChargeResult

type ChargeResult struct {
	// Challenge is returned when the client still needs to satisfy the payment.
	Challenge *mpp.Challenge
	// Credential is the verified client credential on success.
	Credential *mpp.Credential
	// Receipt acknowledges a successfully verified payment.
	Receipt *mpp.Receipt
}

ChargeResult is either a Challenge or a verified (Credential, Receipt) pair.

func (*ChargeResult) IsChallenge

func (r *ChargeResult) IsChallenge() bool

IsChallenge returns true if the result is a 402 challenge.

type ComposeConfig

type ComposeConfig struct {
	Mpp    *Mpp
	Params ChargeParams
}

ComposeConfig pairs an Mpp instance with the ChargeParams for one payment method. Pass one or more of these to ComposeMiddleware to advertise multiple payment options on a single route.

type Intent

type Intent interface {
	Name() string
	Verify(ctx context.Context, credential *mpp.Credential, request map[string]any) (*mpp.Receipt, error)
}

Intent is the interface for payment intents (server-side verification).

type Method

type Method interface {
	Name() string
	Intents() map[string]Intent
}

Method is the interface for server-side payment methods.

type Mpp

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

Mpp is the server-side payment handler.

func New

func New(method Method, realm, secretKey string) *Mpp

New creates an Mpp instance.

func (*Mpp) Charge

func (m *Mpp) Charge(ctx context.Context, params ChargeParams) (*ChargeResult, error)

Charge handles a charge intent with human-readable amounts.

func (*Mpp) Realm

func (m *Mpp) Realm() string

Realm returns the WWW-Authenticate realm used by this payment handler.

type VerifyParams

type VerifyParams struct {
	// Authorization is the incoming Authorization header value.
	Authorization string
	// Intent verifies Credentials for this request.
	Intent Intent
	// Request is the canonical request shape the Challenge binds to.
	Request map[string]any
	// Body is the actual request body bytes/string/object the digest binds to.
	// When set, issued challenges include a body digest and submitted
	// credentials must echo a digest matching this value.
	Body any
	// Realm is the expected server realm.
	Realm string
	// SecretKey signs and verifies Challenge IDs.
	SecretKey string
	// Method is the payment method token, for example "tempo".
	Method string
	// Description is copied into a newly issued Challenge.
	Description string
	// Meta stores opaque Challenge metadata.
	Meta map[string]string
	// Expires overrides the default Challenge expiry.
	Expires string
}

VerifyParams contains the parameters for VerifyOrChallenge.

type VerifyResult

type VerifyResult struct {
	// Challenge is returned when the server needs the client to pay first.
	Challenge *mpp.Challenge
	// Credential is the parsed client credential on success.
	Credential *mpp.Credential
	// Receipt acknowledges successful verification.
	Receipt *mpp.Receipt
}

VerifyResult is either a Challenge or a verified (Credential, Receipt) pair.

func VerifyOrChallenge

func VerifyOrChallenge(ctx context.Context, params VerifyParams) (*VerifyResult, error)

VerifyOrChallenge checks for a valid payment credential or generates a new challenge. Returns a Challenge if payment is required, or (Credential, Receipt) if verified.

Logic:

  1. If no authorization header, create new challenge
  2. Extract "Payment" scheme from Authorization header
  3. Parse credential
  4. Recompute expected challenge ID from echoed parameters via HMAC
  5. Constant-time compare IDs
  6. Verify echoed fields match (realm, method, intent name, request)
  7. Check expiry
  8. Verify body digest, if present
  9. Call intent.Verify
  10. Return result

Directories

Path Synopsis
Package echoadapter provides Echo middleware for MPP-protected routes.
Package echoadapter provides Echo middleware for MPP-protected routes.
Package fiberadapter provides Fiber middleware for MPP-protected routes.
Package fiberadapter provides Fiber middleware for MPP-protected routes.
Package ginadapter provides Gin middleware for MPP-protected routes.
Package ginadapter provides Gin middleware for MPP-protected routes.

Jump to

Keyboard shortcuts

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