feat: multi-chain MPP support (Solana + Tempo)#155
Merged
Conversation
Server now emits an array of MPP challenges (one per supported chain) instead of a single Tempo-only challenge. Client extracts all challenges and forwards the array to accounts, which picks the chain via feature flag. Uses X-MPP-Payment header to carry the MPP credential alongside the OAuth Bearer token without conflicts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shared core for building protocol-specific payment data from destination sources. Used by both requirePayment() (MCP servers) and LLM callers. - buildPaymentOptions: sources → X402 requirements + MPP challenges - buildAuthorizeParamsFromSources: thin wrapper returning AuthorizeParams fields - requirePayment refactored to use buildPaymentOptions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Standard MPP uses Authorization: Payment which conflicts with OAuth's Authorization: Bearer. Instead of a custom header (X-MPP-Payment): - Server signs user identity into MPP challenge opaque field (HMAC) - Client sends standard Authorization: Payment (interop preserved) - OAuth fetch skips Bearer when Payment is present - Server recovers identity from opaque on retry (HMAC verified) This preserves interop with external MPP clients/servers while solving the OAuth header conflict for ATXP-to-ATXP flows. Also: challenge ID uniqueness (random suffix), detectProtocol cleanup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nt ordering - Fix OAuth bypass to only skip challenge for ATXP/X402 (separate headers) or MPP when opaque identity verification succeeds; MPP with failed/missing opaque still gets OAuth challenge (#13) - Extract parseCredentialBase64 helper for try-base64-then-raw-JSON pattern, use in atxpExpress.ts and protocol.ts (#14) - Add opaqueIdentity unit tests: round-trip, tampered sig, wrong challengeId, missing opaque, malformed fields, different sub (#11) - Align MppChallengeData.opaque type to Record<string, unknown> (#16) - Reorder getSources after getExistingPaymentId check in requirePayment to avoid unnecessary fetch on idempotent path; extract fetchAllSources (#6) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ests - mppProtocolHandler: stop reporting challenge ID as transactionHash; use AuthorizeResult.context if available, empty string otherwise. Use context.network for settled chain when available. - opaqueIdentity: derive HMAC key from ATXP_OPAQUE_KEY env var with random fallback for multi-instance deployments. - oAuth: add inline comment referencing buildPaymentHeaders contract. - omniChallenge.test: add tests for buildPaymentOptions and buildAuthorizeParamsFromSources covering multi-chain scenarios. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Changed buildMppChallenges fallback from 'pathUSD' to 'USDC' since Tempo mainnet now uses USDC as the default stablecoin. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
buildMppChallenges()now returns an array of challenges (one per supported chain: Solana USDC + Tempo pathUSD) instead of a single Tempo-only challenge.OmniChallenge.mppis nowMppChallengeData[]. Both HTTP (WWW-Authenticatewith multiplePaymentvalues per RFC 7235) and MCP (data.mppas array) formats support the array.X-MPP-Paymentinstead ofAuthorization: Paymentto avoid conflicting with the OAuthAuthorization: Bearertoken. ServerdetectProtocol()checks this header first, with fallback to standardAuthorization: Payment.MPPProtocolHandlerextracts all challenges from headers/MCP errors and sends the fullchallenges[]array to accounts service, which picks the chain viaff:mpp-chainfeature flag.Packages changed
@atxp/serverbuildMppChallenges()(array),detectProtocol()checksx-mpp-payment, omni-challenge emits array@atxp/mppparseMPPHeaders(),parseMPPChallengesFromMCPError()handle arrays@atxp/clientX-MPP-Paymentheader@atxp/commonAuthorizeParams.challengesfield added@atxp/expressx-mpp-paymentheader to protocol detectionTest plan
omniChallenge.test.ts)paymentHeaders.test.tsupdated forX-MPP-PaymentprotocolHandler.test.tsupdated forX-MPP-Paymentchallenges[]array in/authorize/auto🤖 Generated with Claude Code