x402 client: strict `resource.url === response.url` equality rejects valid query-parameterized resources
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 176
- Forks
- 66
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 52
Description
What happened
Using mppx@0.10.1's x402 client directly (mppx/client + mppx/evm/client), a purchase against a real, spec-compliant x402 v2 door failed client-side, before any signature was attempted:
Error: x402 payment-required resource does not match response URL.
Traced to dist/client/internal/protocols/X402.js:
if (response.url && paymentRequired.resource.url !== response.url)
throw new Error('x402 payment-required resource does not match response URL.');
This does a strict string equality between the resource.url declared inside the 402 envelope and the actual fetched response.url.
Why it breaks a valid case
The door in question requires a query parameter on the paid request (e.g. ?summary=...) — the resource server's own 402 body says as much, and refuses the purchase without it. The server declared resource.url as the bare path (https://example.com/api/buy/thing, no query string), since that's the canonical/logical resource identity. The actual request necessarily carries the required query string, so resource.url !== response.url is guaranteed to be true for any door that requires query input — the check can never pass for that entire class of resource, regardless of whether the request is otherwise perfectly valid.
Spec basis
Per specs/x402-specification-v2.md in x402-foundation/x402, the ResourceInfo.url field is documented only as "URL of the protected resource" — there's no stated requirement that it be byte-identical to the request URL used to fetch it, including query string. Treating it as an exact-match anti-tampering check seems like a reasonable defensive choice, but it's stricter than the spec actually requires, and as written it can't be satisfied by any resource that legitimately needs a query parameter.
Suggested fix
Compare on origin + pathname (ignoring query string), or make the check configurable, rather than full-URL string equality. Happy to open a PR if that's a useful shape for it — wanted to flag the spec-vs-implementation gap first in case there's a reason for the current strictness I'm not seeing.
Repro
Any x402 v2 resource server that (a) requires a query parameter on the paid request and (b) declares its resource.url without that query string (a very natural implementation choice) will reject 100% of purchase attempts made through this client's x402 path. Found this hitting our own store's checkout while testing a native MPP integration.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at dist/client/internal/protocols/X402.js and trace the x402 path used by mppx/client and mppx/evm/client, then compare its URL validation with the ResourceInfo.url wording in specs/x402-specification-v2.md. Done means valid resources whose requests add query parameters are accepted while genuinely mismatched resources remain rejected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, payments
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100