Skip to content

feat: RFC 9457 problem+json on payment challenges#302

Open
stevencartavia wants to merge 4 commits into
tempoxyz:mainfrom
stevencartavia:feat-problem-details
Open

feat: RFC 9457 problem+json on payment challenges#302
stevencartavia wants to merge 4 commits into
tempoxyz:mainfrom
stevencartavia:feat-problem-details

Conversation

@stevencartavia

Copy link
Copy Markdown
Contributor

402 challenge/re-challenge responses now return an RFC 9457 application/problem+json body typed by the failure (malformed-credential, verification-failed, etc.), instead of generic application/json {"error":...}.

Breaking Change:

  • ChallengeContext.error: Option<&str>Option<&MppError>
  • PaymentRequired: tuple → struct { challenge, error } (use new/with_error)
  • ChargeChallenger::{challenge,verify_payment,verify_payment_for_amount} return MppError not String
  • HTTP 402 body/content-type changed (wire break)

Only affects code that hand-implements Transport/ChargeChallenger or parses the old 402 body. Tower middleware unchanged.

mattsse commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

One issue to fix before merging: the new axum path converts verification failures with .map_err(MppError::from) before rendering the application/problem+json body, for both Tempo verification and Stripe verification. The extractor then carries that converted error into PaymentRequired::with_error(...) and uses it for the 402 problem response here.

That conversion currently collapses several typed VerificationError codes into MppError::VerificationFailed in the catch-all arm here, even though those codes already declare more specific spec mappings such as malformed-credential, payment-insufficient, and method-unsupported here. Once collapsed, MppError::to_problem_details renders them as verification-failed here, so failures that already have typed codes lose the specific problem type this PR is trying to expose.

Concrete examples: CredentialMismatch from route replay / HMAC checks should map to malformed-credential, InvalidAmount should map to payment-insufficient, and ChainIdMismatch should map to method-unsupported per ErrorCode::spec_code().

Suggested fix: align impl From<VerificationError> for MppError with ErrorCode::spec_code() (or render VerificationError directly without lossy conversion). For example, map CredentialMismatch | InvalidCredential | InvalidPayload to malformed credential, InvalidAmount | InsufficientBalance to payment insufficient, ChainIdMismatch to method unsupported, Expired to payment expired, and keep only the generic verification cases as VerificationFailed. I’d also add an axum regression test that replays a credential across routes / amounts and asserts the 402 problem type is the expected specific URI rather than verification-failed.

@stevencartavia stevencartavia changed the title RFC 9457 problem+json on payment challenges feat: RFC 9457 problem+json on payment challenges Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants