Skip to main content

White Label

This document describes how to configure Marble's White Label feature. This enables applications to provide users with self-custodial wallets without having to build their own wallet infrastructure.


  • Bring your own auth.
  • Self-custodial. Neither Marble nor the application has access to the user's wallet.
  • Cross-app compatible. Marble is not an application specific wallet.
  • Multi-chain by design.
  • Secured by Multi Party Computation (MPC).

This is an enterprise-only feature that needs to be enabled by Marble. Please contact us at to enable it.

User Flow

The user flow for White Label is as follows:

  1. User authenticates with the application.
  2. User clicks “Create Wallet” to generate a self-custodial wallet (or is prompted to create a wallet if they don’t have one).
  3. User receives a white labeled email / text / pin / 2FA from Marble to verify identity.
  4. dApp can fully customize the marble-sdk, send transactions, etc.

Getting Started

0. Prepare your application

Your application will need to save a secret for the user. This effectively replaces the password of the user in the regular Marble authentication flow with the modal.

To support this, the application needs to implement a mechanism to store and retrieve a unique secret for the user. The implementation may look like the following, assuming that there exists a typical server - database infrastructure with a User table in the database.

  1. Create an additional schema / table (depending on your database engine) named marble_auth_secret with user_id and secret as columns.
  2. Generate a random string with a high entropy to be used in the secret column. uuidv4 works. This can be generated before requesting to Marble or this can be generated on user creation.
  3. Expose an authenticated GET API to be used on the application’s frontend that would fetch the secret given the user’s authentication credentials.

The fetched secret from marble_auth_secret will be provided to our SDK, which Marble will use to authenticate the user and decrypt the user’s MPC share. The pseudocode for how this flow will look like is provided below.

1. Authenticate the user with your application and retrieve the user's secret

// User authenticates with your application (this should not change)
const token = await fetch("<application_server>/authenticate", "POST", { email, password or oAuthToken? });
// User fetches the secret from your application's server
const userSecret = await fetch("<application_server>/marble/secret", "GET", { token });

2. Authenticate with Marble's server (white label)

const marbleSDK = new Marble("<YOUR_CLIENT_KEY>");

// Authenticate user with Marble using the secret from your application's server.
// Note: This will send an SMS code to the user's phone number. The SMS is configured in Marble's dashboard.
// Note: Here, we also support email authentication or 2FA (coming soon).
await marbleSDK.auth.sendAuthenticationCode(AuthMethod.SMSCode, userPhoneNumber);
const user = await marbleSDK.auth.authenticateWithSecret(
smsCode // smsCode here is the 6-digit code that the user should've received.

3. Use Marble as you would normally

Note that given we know the YOUR_CLIENT_KEY and the host from where the request is coming from, we can enable approval-less signatures.

// This will return true if the user is currently logged in. 
const isLoggedIn = await marbleClient.auth.isLoggedIn();

* This will return the list of addresses owned by the user grouped by the chain.
* @returns {<name of the chain>: string[]}
const addresses = await marbleClient.api.getAddressList({});

// The signature flow can be the same as how you would typically request for signatures, whether using ethers.js or Wagmi.
// Signing a transaction using ethers.js
const provider = new ethers.providers.Web3Provider(marbleClient.rpcProvider);
const signer = provider.getSigner();
const result = await signer?.signMessage("Hello world!");

Maintaining non-custodial property

This section describes how even with relaxing the secret ownership (application owning the password with this enterprise plan rather than the user providing it) still maintains the non-custodial nature of the wallet.

The non-custodial-ness comes from an additional verification step that Marble will have directly with the user. This will be an email magic link / email code / sms code. It can be branded to be coming from the application’s email (non email address) so that you own the customer-facing relationship. This way, the following properties are achieved:

  1. Marble does not have unilateral access to user’s accounts

    Marble stores the encrypted user share, where the encryption happens using the secret kept in the application. The raw secret never reaches Marbles’ backend infrastructure. This means that only on the frontend once the secret is provided can one decrypt the user’s share.

    Strawman counter-argument: “But since this is on an iframe which is Marble’s React code, Marble could just use the encrypted user share.” This applies to any non-custodial wallet code - a purported non-custodial wallet can have a malicious code push that logs all the user’s seed phrase to DataDog for example. We are awaiting audits, and we are also willing to share our code (to be open-sourced) to prove that our frontend never communicates the raw secret or raw user share to the backend.

  2. Application does not have unilateral access to user’s accounts

    Marble will perform the verification step with the user directly effectively checking their ownership of the email or the phone number. Since the application’s frontend does not own the user’s device or actual email accounts, the application will not be able to pretend that it is the user. In addition, the decrypted user share remains on the iframe of Marble’s frontend. These imply that even though the secret is in the possession of the application, it alone cannot obtain the rights to the user’s secret (since the user needs to verify themselves), nor have access to it (since it is not in the premise of the application’s frontend).

For more details on how client side encryption / decryption of the user share using the secret happens for our MPC infrastructure, refer to