Skip to main content

Overview

Mesh’s Managed Tokens system (MMT) is a service designed to simplify how clients manage user authentication tokens. Rather than requiring clients to handle the lifecycle of access and refresh tokens for each integration, MMT securely stores and manages tokens on behalf of the client. Clients receive a persistent tokenId that can be used to create a clean return user experience for exchanges, and to interact with certain Mesh APIs without needing to refresh or re-authenticate.

Benefits

  • Simplified Token Lifecycle: Clients do not need to handle the storage or refresh logic for tokens directly.
  • Streamlined UX: End-users can skip repetitive authentication steps, enhancing the embedded experience.
  • Persistent Access (where supported): For exchange integrations that provide long-lived or refreshable tokens (e.g., Coinbase), the same tokenId remains valid indefinitely. For integrations with expiring tokens (e.g., Binance), users may still need to re-authenticate, but the tokenId remains unchanged, allowing clients to reuse it without needing to update backend storage.
  • Seamless Re-authentication: When a token expires (e.g., Binance), Mesh Link will prompt the user to re-authenticate. Once complete, the same tokenId is revalidated and continues to work as before—reducing backend complexity for clients.
  • Integration-Agnostic: Works across different auth methods (OAuth, credentials-based) with no added client-side complexity.

How to Implement MMT

1. Obtain a tokenId

When a user authenticates with their exchange or wallet account, you will receive the SDK event integrationConnected, which contains an object like this:
{
    "accessToken": {
        "accountTokens": [
            {
                "account": {
                    "meshAccountId": "<meshAccountId>",
                    "frontAccountId": "<frontAccountId>",
                    "accountId": "<accountId>",
                    "accountName": "<accountName>",
                    "fund": 0,
                    "cash": 0
                },
                "accessToken": "<accessToken>",
                "tokenId": "<tokenId>"
            }
        ],
        "brokerType": "<brokerType>",
        "brokerName": "<brokerName>",
        "brokerBrandInfo": {}
    }
}
Pull out the tokenId and brokerType values and construct the following object. Because Mesh will be managing the token refresh logic for you, you’ll be providing the tokenId value from the SDK event in the accessToken field in this object. This will be used when initializing future sessions of the Mesh SDK for this user. Note: The brokerName, accountId, and accountName fields are obsolete but must still be passed (can be empty) when initializing the SDK.
const accessTokens: IntegrationAccessToken[] = [
  {
    accessToken: '<accessToken>',
    brokerType: '<brokerType>',
    brokerName: '',
    accountId: '',
    accountName: ''
  }
]
Important: Be sure to maintain a strict mapping to the appropriate user.

2. Pass the accessTokens object to the Mesh SDK

You can pass this object (including one tokenId, or multiple if the user has authenticated into multiple different exchange accounts) into the Mesh Link SDK so that user can skip re-authentication and proceed directly into the transfer or portfolio flow. SDK Setup Example:
const connection = createLink({
  clientId: 'abc123', // Replace Mesh Client ID
  theme: 'system', // Possible values: 'system', 'dark', 'light'
  language: 'system', // Refer to the Enabling Multi-Language Support Document
  displayFiatCurrency: 'USD' // Refer to the Foreign Currency Support Document
  accessTokens: accessTokens, // This references the IntegrationAccessToken[] constant
  onIntegrationConnected: payload => {
    console.debug('[MESH LINK integration connected]', payload) // Payload contains integration tokens that can be used for a return user experience or calling certain Mesh APIs
  },
  onTransferFinished: payload => {
    console.debug('[MESH LINK transfer finished]', payload) // Payload contains pending transfer data
  },
  onExit: () => {
    console.debug('[MESH LINK exited]') // Payload contains error and session summary
  },
  onEvent: ev => {
    console.debug('[MESH LINK event]', ev) // Allows you to handle other specific events
  }
})

connection.openLink(linkToken) // open in popup iframe
Link: Enabling Multi-Language Support Link: Foreign Currency Support If the account accessToken associated with the tokenId is no longer valid, Link will prompt the user to re-authenticate and automatically update the accessToken associated with that tokenId, meaning no update is required on your end.

4. Token Lifecycle and Behavior

ScenarioResult
Same user reconnects with same integrationReturns same TokenId
Different user connects to same integrationReturns a new TokenId
Same user connects with different scopes (e.g., read vs write)Returns distinct TokenIds per scope
Write endpoint called using read-only TokenIdAPI returns a scope mismatch error
Token revoked by client (use Remove connection endpoint)Associated access is permanently disabled and Mesh also deletes the token physically, without any way to restore it

Supported Integrations (as of today)

  • Coinbase (OAuth)
  • Binance (Username/Password)
  • Uphold (OAuth)
  • Note: connections with self-custody wallets are maintained on subsequent sessions (unless the user actively kills the connection in their wallet app) without the need for handling tokens. This means the same smooth return user journey is achieved for wallet transactions.
For testing with sandbox accounts, see our sandbox guide.

Security Considerations

While MMT streamlines token handling and unlocks powerful functionality, it also requires thoughtful security practices given its expanded role in managing user access. Mesh has designed the system with robust safeguards to ensure token integrity and data protection, including:
  • Encrypted Storage: All tokens are encrypted at rest using modern encryption standards.
  • Scoped Access: Each TokenId is tied to the permission scope (read or write) associated with the API key. Unauthorized operations (e.g., calling a write endpoint with a read-scoped token) will be rejected.
  • Client-Level Isolation: Each TokenId is also scoped to a specific clientId. Even if the same end user connects the same integration account across multiple client apps, the tokens are isolated and not shared across clients.
  • User-Level Isolation: Each TokenId is unique to a specific EndUserId and integration.
  • Token Revocation: Clients can revoke a TokenId, permanently disabling access and triggering a secure deletion process. There is no path to restore a revoked token.