Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

mpp pay always fails against mppx >= 0.15 servers: "MPP challenge changed after approval" (per-challenge nonce in opaque is not excluded from the comparison)

Đang mở
#486 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@staubman-stripe đang làm issue này rồi.

Từ ngày 27/10/2026.

  • #490 của @staubman-stripe — đang mở

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
72/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
node.js, typescript
Lĩnh vực
cli, payments

Hướng nghiên cứu

Start in comparableChallenge in link-cli, which the issue identifies as neutralizing id and expires before the approved challenge is compared with a fresh probe. Read the challenge serialization and approval comparison flow, including payPinnedChallengeWithSpt and runMppPayFullFlow. Reproduce with an mppx 0.15 server and verify the same approved payment succeeds when only issuance metadata differs.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Summary

Against a seller using mppx 0.15.0 (Stripe SPT charge), link-cli mpp pay can never complete a payment. After the spend request is approved, link-cli re-probes the endpoint and compares the fresh 402 challenge to the approved one. mppx adds fresh random issuance metadata (_mppx_nonce) to every challenge's opaque field by design, so the comparison always fails:

Error: MPP challenge changed after approval; refusing to use the approved payment credential

The amount, currency, realm, method, intent, request, and description are identical between the two challenges. Only id, expires, and the nonce in opaque differ.

Versions
  • @stripe/link-cli 0.30.0
  • mppx 0.15.0 (server: Mppx from mppx/server/core with stripe.spt(...) from mppx/stripe/server/spt)
  • Node.js 20 and 24, Stripe test mode, --test
Steps to reproduce
  1. Run an MPP endpoint with mppx 0.15.0 and a Stripe SPT charge, for example mppx.charge({ amount: '0.75', currency: 'usd', decimals: 2 })(request).
  2. link-cli mpp pay <url> --method POST --data '<json>' --test --context "<100+ chars>"
  3. Approve the spend request in Link.
  4. Run the returned _next.pay_argv (mpp pay <url> --spend-request-id <id> --approved-challenge '<challenge>' ...).
  5. It fails with the error above. The interactive (TTY) flow fails the same way, because runMppPayFullFlow also ends in payPinnedChallengeWithSpt(probe, spt, approvedChallenge).
Cause

comparableChallenge in link-cli only neutralizes id and expires:

function comparableChallenge(challenge) {
  return Challenge2.serialize({ ...challenge, id: "approval-comparison", expires: void 0 });
}

mppx adds a fresh nonce to every issued challenge (server/internal/challengeMeta.js):

/** Reserved metadata key for HMAC-bound, per-issuance challenge randomness. */
const nonceKey = '_mppx_nonce';
export function withNonce(meta) { return { ...meta, [nonceKey]: Secp256k1.randomPrivateKey() }; }

/** Removes issuance-only metadata when comparing stable route requirements. */
export function routeMeta(meta) { const { [nonceKey]: _, ...rest } = meta ?? {}; ... }

withNonce is applied in server/Mppx.js when challenges are created, so two challenges for the same route are never byte-identical. mppx's own routeMeta() shows the intended comparison: strip _mppx_nonce.

Suggested fix

In comparableChallenge, also drop issuance-only metadata from opaque, specifically the _mppx_nonce key, mirroring mppx's routeMeta(). Alternatively, compare only the fields the shopper actually approved (realm, method, intent, decoded request: amount, currency, network ID, external ID).

Workaround

The approved token itself is valid. Retrieving it with spend-request retrieve <id> --include shared_payment_token and paying a fresh challenge with the mppx client (stripe.charge({ createToken: () => spt })) succeeds. The SPT's own limits (amount, network ID, expiry) still apply.

Ngôn ngữ chính
TypeScript
Star
873
Fork
147
Merge trung bình
23 giờ 53 phút
Pull request đã merge (30 ngày)
76

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của stripe/link-cli

Tất cả issue của stripe/link-cli

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.