Skip to main content
Clink MCP lets a server-side agent call Clink tools on behalf of an authorized user.
Reuse one OAuth client_id for the same server application, deployment, tenant, or installation. Each user completes OAuth separately, and the server stores that user’s tokens. Do not register a new client for every request or user.

Choose a client registration method

Choose the method that matches where your agent runs and whether it can host public HTTPS metadata. The three methods differ in how you obtain client_id and where the client’s redirect URIs and scopes are registered. After you have a client ID, use the same user authorization, callback, MCP request, and token refresh flow described below.

Environments and endpoints

Declare the environment base URLs once, then append the endpoint path shown in each table:
Use the resource URL for the environment where the request will run. The OAuth resource and token audience must exactly match that environment’s MCP URL.
MCP configuration contains only the MCP address. Never put an access token, refresh token, or API key in the MCP configuration.
The OAuth endpoint paths are the same in both public environments. Use each path with the base_url for the selected environment. The authorization and token paths should come from Authorization Server Metadata instead of being hardcoded when available.
Call the DCR registration endpoint only when Authorization Server Metadata includes registration_endpoint. Protected Resource Metadata does not provide a DCR address. If it is absent, use CIMD or Pre-registration.

Registration and authorization frequency

Server-side integration

Prepare the OAuth Client

Whichever method you use, the scopes registered for the client are the upper limit for every authorization request. A request for any scope outside that set fails with invalid_scope, including a later request for more access. Register every scope your agent may need. Clink MCP uses the following scopes, and offline_access lets Clink issue refresh tokens:
Each authorization request can still ask for a subset of these scopes.

CIMD

CIMD is suitable for a server-side agent that can maintain public HTTPS metadata. Host a public JSON file and use its URL as client_id:
Clink fetches this file to validate authorization requests. The file must meet these requirements:
  • The URL uses HTTPS, includes a path, and has no query string or fragment.
  • The client_id in the file exactly matches the file URL.
  • The URL returns HTTP 200 directly with Content-Type: application/json. Redirects are not followed.
  • The file is 5 KB or smaller.
The CIMD URL is a public client identifier. Do not put a client secret in the file.

Pre-registration

Pre-registration is suitable for a fixed enterprise or partner. Before integration, provide Clink with your client_name, fixed HTTPS redirect_uri, the environment’s resource, and every scope your agent may need. Clink configures the client and returns a fixed client_id; your server does not call a registration endpoint and does not need to host a CIMD file. Clink’s pre-registered MCP client is a public client. It does not need a client secret, but it must use Authorization Code with PKCE (S256). Store the returned client ID in server configuration:
When a user selects Connect Clink, use this fixed client ID in the authorization request. Store each user’s tokens separately.

DCR

DCR is suitable when you need a dynamic client ID per tenant or installation, or when the authorization server supports only dynamic registration. First read Authorization Server Metadata. Call the returned registration_endpoint only if it is present. Register once during deployment, tenant activation, or first installation, then persist the returned client_id for all users:
The current Clink flow uses a public client (token_endpoint_auth_method=none), so it does not need a client secret. A successful DCR response only means that the client was registered; every user still signs in and authorizes separately. Clink does not support updating a registered client. To change its redirect URIs or scopes, register a new client; users then authorize again under the new client_id.

Authorize a user

When a user selects Connect Clink:
  1. Fetch the current environment’s Protected Resource Metadata. For Sandbox (UAT), use ${UAT_BASE_URL}/.well-known/oauth-protected-resource/mcp, then read an issuer from authorization_servers.
  2. Fetch {issuer}/.well-known/oauth-authorization-server and read authorization_endpoint and token_endpoint. Do not hardcode these values.
  3. Generate a cryptographically random state and PKCE code_verifier for the user. Temporarily bind them to your internal user ID, and derive an S256 code_challenge.
  4. Redirect the user to the authorization endpoint. URL-encode every parameter.
Set client_id according to the registration method:
  • CIMD: the public JSON file URL.
  • Pre-registration: the fixed client ID returned by Clink.
  • DCR: the persisted client ID returned by registration.
The redirect_uri, resource, state, and PKCE parameters are handled the same way for all three methods.
Request the scopes your integration needs now, within the client’s registered scopes. The MCP server’s first 401 challenge asks for wallet:read events:read events:consume; requesting both events scopes up front avoids a second consent while an operation is in progress. Include offline_access when you need a refresh token. Keep the resource matched to the selected environment.

Exchange the authorization code

After authorization, the callback receives code, state, and iss, or error parameters if authorization failed. Reject the callback if state does not match the stored value, or if iss is missing or differs from the issuer in Authorization Server Metadata. Then send a POST request to token_endpoint with Content-Type: application/x-www-form-urlencoded. Use the same redirect URI and the stored PKCE verifier, and URL-encode each value:
This is a public client, so do not send client_secret or device_id. Encrypt and store access_token, refresh_token, expiration, and scopes by internal user ID, environment, and client_id. An authorization code can be redeemed only once.

Call MCP

Use the current user’s access token to call the /mcp resource for the same environment. Clink MCP supports protocol versions 2026-07-28 and 2025-06-18. Use an official MCP client SDK when possible: it negotiates the version, sends the required headers, and parses streamed responses. Point the SDK at the MCP URL and supply the current user’s access token at runtime as an Authorization: Bearer header. If you send HTTP requests yourself, use the 2025-06-18 flow. Version 2026-07-28 has no initialize handshake and adds protocol metadata to every request, so leave it to an SDK.
  1. Send initialize with protocolVersion set to 2025-06-18.
  2. Send notifications/initialized.
  3. Call tools/list to discover available tools.
  4. Call tools/call to execute a business operation.
Include the Accept header on every request; without it, the server returns 406. The server may stream a response as text/event-stream, where each data: line holds one JSON-RPC message. After initialize, send the negotiated version in an MCP-Protocol-Version header on every later request:

Handle user redirects

Some tool results include a next_action whose type is REDIRECT_USER, for example to add a card, complete 3DS, or register a card for Agent Pay. Send params.redirect_url to the user through your own channel. When params.actor is USER_DEVICE_ONLY, the user must open the link on their own device; do not open it in an agent-controlled browser. Returning from the page does not prove that the step succeeded. Call get_operation to read the result.

Refresh tokens and recover

When an access token expires, submit the following to the same token_endpoint:
  • grant_type=refresh_token
  • The original client_id
  • The current refresh token
  • The same resource used for authorization
Each refresh returns a new refresh token and retires the old one. Store the new refresh token before you use the new access token. If a retired refresh token is sent again, Clink treats it as token reuse and revokes all refresh tokens from that authorization, so the user must authorize again. Serialize refreshes for each user, environment, and client_id, including across server instances.
  • For 401, refresh the token. If refresh fails, send the user through authorization again.
  • For 403 with insufficient_scope, read the required scopes from the scope parameter of the WWW-Authenticate header. Combine them with the scopes already granted, then authorize the user again. The combined scopes must stay within the client’s registered scopes.
  • If a payment, refund, or instruction times out, call get_operation to inspect its status. Do not repeat the operation blindly.

Launch checklist

  • Register the OAuth client only during initialization, deployment, tenant activation, or first installation.
  • Register every scope your agent may need, and request only the scopes you need at authorization time.
  • Isolate each user’s tokens, sessions, and operations.
  • Match the callback URL character for character with the client configuration.
  • Keep tokens and any client secret out of configuration files, CIMD files, and logs.
  • Keep Sandbox (UAT) and Production resources separate.
  • Serialize refresh token use per user, environment, and client_id.
  • Send REDIRECT_USER links to the user instead of opening them in an agent-controlled browser.