MPP.Plug (mpp v0.6.0)

Copy Markdown View Source

Plug middleware implementing the MPP 402 payment handshake.

Mount this plug in any Phoenix or Plug router to gate endpoints behind payment. Each route gets its own pricing via plug opts — no global config.

Single-Method Usage

plug MPP.Plug,
  secret_key: "your-hmac-secret",
  realm: "api.example.com",
  method: MyApp.Payments.Stripe,
  amount: "1000",
  currency: "usd"

Multi-Method Usage

Accept multiple payment methods per endpoint. Each method can have its own pricing and config. The 402 response includes one WWW-Authenticate header per method; the agent picks whichever it can pay with.

plug MPP.Plug,
  secret_key: "your-hmac-secret",
  realm: "api.example.com",
  methods: [
    [method: MyApp.Payments.Stripe, amount: "1000", currency: "usd",
     method_config: %{"stripe_secret_key" => "sk_..."}],
    [method: MyApp.Payments.Tempo, amount: "950", currency: "usd"]
  ]

Flow

  1. Request without Authorization: Payment → 402 with WWW-Authenticate challenge(s)
  2. Client pays off-band, retries with Authorization: Payment <credential>
  3. Valid credential → request passes through with Payment-Receipt header + receipt in assigns
  4. Invalid credential → 402 with fresh challenge(s) + RFC 9457 error body

Shared Options

  • :secret_key — (required) HMAC-SHA256 key for challenge binding
  • :realm — (required) server protection space
  • :expires_in — (optional) challenge TTL in seconds (integer)
  • :opaque — (optional) base64url-encoded server correlation data

Single-Method Options

  • :method — (required) module implementing MPP.Method
  • :amount — (required) price in base units (string)
  • :currency — (required) currency code (string, normalized to lowercase)
  • :recipient — (optional) payment recipient identifier
  • :description — (optional) human-readable description
  • :method_config — (optional) server-only config map for verify/2

Multi-Method Options

  • :methods — (required) list of keyword lists, each with per-method opts: :method, :amount, :currency, and optionally :recipient, :description, :method_config

Summary

Functions

Runs the MPP 402 payment handshake for the current request.

Builds validated plug configuration from options at init time.

Functions

call(conn, config)

@spec call(Plug.Conn.t(), MPP.Plug.Config.t()) :: Plug.Conn.t()

Runs the MPP 402 payment handshake for the current request.

Returns 402 with fresh challenges when no valid credential is present; halts with an RFC 9457 problem body on verification failure; otherwise passes the connection through with :mpp_receipt assigned and a Payment-Receipt response header.

init(opts)

@spec init(keyword()) :: MPP.Plug.Config.t()

Builds validated plug configuration from options at init time.

Normalizes single- or multi-method opts into a %Config{} with one MethodEntry per accepted payment method. Raises on missing required options or duplicate method names.