Skip to main content
This page covers the platform layer around Browser Pay: credentials, per-user OAuth connections, tenant isolation, and deployment checks. Browser Pay can coexist with Vault SDK in the same platform; route a checkout to one path before the payment attempt starts. It does not repeat the payment state machine. For the checkout flow, credential handling, result reporting, and recovery, use the Browser Pay guide.
A platform has two OAuth concerns. Its server uses the platform credential pair to manage user connections; each user then authorizes a separate MCP connection with Authorization Code + PKCE. Clink may register the same client_id for both roles, but the client_secret never goes through the user authorization flow.

Prepare the platform integration

Ask Clink to provide or confirm the following for each environment: For the user OAuth client, choose CIMD, pre-registration, or DCR as described in MCP connection and OAuth. OAuth client registration and RSA public-key registration are separate steps. Browser Pay normally needs these user scopes:
Add wallet:setup when the platform changes a user’s default card. The registered OAuth client must allow every scope requested by the authorization flow. Scope details and tool-specific requirements belong in the Browser Pay guide and Browser Pay API reference.

Establish each user connection

Keep the platform token and user token in separate stores. The platform token calls the partner connection endpoints; the user token represents one user when the platform calls MCP. The platform connection has two phases: the server creates or manages the Clink session, then the user completes Authorization Code + PKCE. Keep the callback state tied to the platform user before opening the MCP connection.

Get a platform token

Use the partner credentials with client_credentials:
Cache access_token until expires_in and obtain a new one after expiry. This token manages platform sessions; it cannot call a user’s MCP tools directly.

Create or resume a user session

When a user enables Clink, generate a random state and PKCE code_verifier, calculate the S256 code_challenge, and bind them temporarily to that platform user. Use a verified user email and your stable external_user_id:
Read data.status from the response. Clink must confirm the formal data schema and field return conditions during enablement: When the callback returns code, state, and iss, verify that the state belongs to the user who started the connection and that iss matches the issuer in the Authorization Server Metadata for the same environment. Do not persist a cancelled or failed connection. Exchange the code at the token_endpoint from Authorization Server Metadata as a public client. Do not send a client_secret:
redirect_uri must exactly match the registered and authorized value. Read token_endpoint and the issuer from {API_BASE_URL}/.well-known/oauth-authorization-server instead of hardcoding them, and never mix UAT and Production. The resource and MCP URL must belong to the same environment.

Persist platform state safely

Use one record per platform user, environment, and OAuth client. Keep the association with external_user_id in the platform database; Clink’s customer_id is not a substitute for the platform user ID. Refresh each user’s token serially, including across server instances. Each refresh returns a new refresh_token and retires the old one: store the new value before using the new Access Token, and never send a retired token again. If a retired token is sent again, Clink revokes every Refresh Token from that authorization and the user must authorize again. If refresh fails, stop new MCP work for that user and restart authorization. See Refresh tokens and recover. When a user disconnects, stop new work, revoke the Refresh Token with the configured OAuth client at /agent/cwallet/oauth/revoke, and remove local credentials. A user with an empty wallet is still connected; a readable wallet or default card does not authorize a purchase. Connect MCP with the user’s token and read the current tool list and clink://skill/rules. If the Host cannot read resources, call get_skill_manifest with include_rules: true. The platform should make a read-only get_account_state call before enabling payment actions. For a Node.js smoke test, use Node.js 20.19 or later and @modelcontextprotocol/client@2: connect to the environment’s MCP URL with the user’s Access Token, list tools, call get_account_state with {}, and inspect structuredContent. Treat isError: true as a failed connection. connected: true plus a readable wallet proves the connection; cardCount: 0 means the wallet is empty, not that OAuth failed. Use the platform’s normal per-user refresh flow after this check.
OAuth grants access to Clink tools; it does not authorize a purchase. A purchase instruction or a one-time user action defines what the Agent may spend. Passkey and other user actions returned by Browser Pay must be presented to the correct user and resumed through the same Operation.

Hand off a checkout to Browser Pay

The platform remains responsible for the merchant browser and the user experience. The canonical Browser Pay guide defines the payment flow; the platform adapter must provide these inputs and handoffs:
  • Read the merchant’s final amount, currency, merchant details, and checkout facts. Use minor currency units and preserve the same facts when resuming an Operation.
  • Refresh the wallet before choosing a specific paymentInstrumentId; let the user confirm the card and use only a card marked agent_pay_support: true.
  • Deliver next_action.params.redirect_url and QR or user-device actions unchanged. Never open a USER_DEVICE_ONLY link in the Agent’s browser.
  • Preserve the issuing Operation and payment identifiers before filling the merchant form. Keep encrypted credentials and decrypted card fields out of model input, logs, and ordinary records.
  • Report the result observed on the merchant page with confirm_result. A Clink report or PSP response does not replace merchant confirmation.
For amount checks, credential decryption, next_action handling, result enums, and duplicate-payment recovery, continue to the Browser Pay guide. For card and purchase authorization management, use Wallet Service.

Validate before rollout

Run these checks in Sandbox UAT and repeat the relevant checks in Production:
  • Two platform users can share an OAuth client while seeing only their own wallet, Operations, and payment context.
  • An already authorized user can obtain a credential; a user action can be presented and resumed through the same Operation.
  • The registered RSA public key decrypts a credential in the trusted platform component, while the secret key and card fields stay out of the Agent and logs.
  • Access Token expiry, Refresh Token rotation, callback replay, user disconnect, and authorization failure have explicit handling.
  • Success, failure, unsubmitted, and unknown merchant outcomes are reported with the correct Clink identifiers and never trigger an automatic duplicate payment.
Before production, confirm the /platform/sessions data schema, the relationship between partner and public OAuth client_id, the OAuth scope registration, the environment resource values, and the public-key registration process. Keep these values in deployment configuration rather than inferring them from examples.