Signers Module

Manage wallet signers and authentication methods

Signers Module

The signers module provides comprehensive functionality for managing wallet signers, including creating different signer types, updating permissions, and managing signer lifecycle.

Import

import { 
  listSigners,
  getSignerById,
  createEmailSigner,
  createPhoneSigner,
  createPasskeySigner,
  createExternalWalletSigner,
  createApiKeySigner,
  updateSigner,
  updateSignerPermissions,
  deleteSigner,
  getCustodyInfo
} from 'cilantro-sdk/signers';

Basic Operations

listSigners(walletId)

List all signers for a wallet (both authentication and on-chain signers).

const signers = await listSigners('wallet-id');
console.log('Wallet signers:', signers.data);

getSignerById(walletId, signerId)

Get detailed information about a specific signer.

const signer = await getSignerById('wallet-id', 'signer-id');
console.log('Signer type:', signer.data.type);
console.log('Signer status:', signer.data.isActive);

getCustodyInfo(walletId)

Get wallet custody information and all signers.

const custodyInfo = await getCustodyInfo('wallet-id');
console.log('Custody type:', custodyInfo.data.custodyType);
console.log('Signers:', custodyInfo.data.signers);

Creating Signers

createEmailSigner(walletId, options)

Create an email-based signer (non-custodial). The user controls their keys via email authentication.

emailstringrequired

Email address for the signer

devicePublicKeystringrequired

Device public key (base64 encoded)

const signer = await createEmailSigner('wallet-id', {
  email: 'user@example.com',
  devicePublicKey: 'base64-encoded-device-public-key'
});

createPhoneSigner(walletId, options)

Create a phone-based signer (non-custodial). The user controls their keys via SMS authentication.

phonestringrequired

Phone number for the signer

devicePublicKeystringrequired

Device public key (base64 encoded)

const signer = await createPhoneSigner('wallet-id', {
  phone: '+1234567890',
  devicePublicKey: 'base64-encoded-device-public-key'
});

createPasskeySigner(walletId)

Create a passkey signer using WebAuthn. This is a two-step process:

Step 1: Start Registration

const options = await startPasskeyRegistration('wallet-id');

Step 2: Complete Registration

// Use browser WebAuthn API
const credential = await navigator.credentials.create({
  publicKey: options.data
});

// Verify and create signer
const signer = await verifyPasskeyRegistration('wallet-id', {
  response: credential.response,
  credentialId: credential.id
});

createExternalWalletSigner(walletId, options)

Link an external wallet (e.g., Phantom, Solflare) as a signer.

publicKeystringrequired

Public key of the external wallet

const signer = await createExternalWalletSigner('wallet-id', {
  publicKey: 'external-wallet-public-key'
});

createApiKeySigner(walletId, options)

Create an API key-based custodial signer. The platform manages the signing keys.

apiKeyNamestringrequired

Name for the API key signer

const signer = await createApiKeySigner('wallet-id', {
  apiKeyName: 'Server Signer'
});

Managing Signers

updateSigner(walletId, signerId, options)

Update signer configuration such as active status or primary designation.

isActiveboolean

Whether the signer is active

isPrimaryboolean

Whether this is the primary signer for the wallet

await updateSigner('wallet-id', 'signer-id', {
  isActive: true,
  isPrimary: false
});

updateSignerPermissions(walletId, signerPubkey, options)

Update signer permissions for on-chain signers.

permissionsobjectrequired

Permissions object

permissions.canSendSolboolean

Can send SOL

permissions.canSendTokensboolean

Can send SPL tokens

permissions.canExecuteCpiboolean

Can execute CPI instructions

permissions.maxTransferAmountnumber

Maximum transfer amount (optional)

permissions.allowedProgramsstring[]

Allowed program public keys (optional)

// Read-only signer
await updateSignerPermissions('wallet-id', 'signer-public-key', {
  permissions: {
    canSendSol: false,
    canSendTokens: false,
    canExecuteCpi: false
  }
});

// Transfer-only signer with limit
await updateSignerPermissions('wallet-id', 'signer-public-key', {
  permissions: {
    canSendSol: true,
    canSendTokens: true,
    canExecuteCpi: false,
    maxTransferAmount: 1000000000 // 1 SOL limit
  }
});

// Full access signer
await updateSignerPermissions('wallet-id', 'signer-public-key', {
  permissions: {
    canSendSol: true,
    canSendTokens: true,
    canExecuteCpi: true
  }
});

deleteSigner(walletId, signerId)

Remove an authentication signer from the wallet. This will also remove it from on-chain registration. At least one signer must remain active.

await deleteSigner('wallet-id', 'signer-id');

At least one signer must remain active. You cannot delete the last active signer.

Device Identity Management

updateDeviceIdentity(walletId, signerId, options)

Replace a device for an email/phone signer while keeping the same signer.

oldDevicePublicKeystring

Old device public key (optional if signer has only one device)

devicePublicKeystringrequired

New device public key

encryptedMasterSecretstringrequired

Encrypted master secret for the new device

await updateDeviceIdentity('wallet-id', 'signer-id', {
  devicePublicKey: 'new-device-public-key',
  encryptedMasterSecret: 'encrypted-secret'
});

getDeviceEncryptedSecret(walletId, signerId, devicePublicKey?)

Retrieve the encrypted master secret for email/phone signers. Used for device-specific key recovery.

const secret = await getDeviceEncryptedSecret(
  'wallet-id',
  'signer-id',
  'device-public-key'
);

Usage Examples

Multi-Signer Wallet Setup

// Create wallet
const wallet = await create({ label: 'Multi-Signer Wallet' });

// Add email signer (primary)
const emailSigner = await createEmailSigner(wallet.data.walletId, {
  email: 'user@example.com',
  devicePublicKey: deviceKey.publicKey
});

// Add phone signer (recovery)
const phoneSigner = await createPhoneSigner(wallet.data.walletId, {
  phone: '+1234567890',
  devicePublicKey: deviceKey.publicKey
});

// Add external wallet signer
const externalSigner = await createExternalWalletSigner(wallet.data.walletId, {
  publicKey: 'phantom-wallet-public-key'
});

// List all signers
const allSigners = await listSigners(wallet.data.walletId);
console.log('Total signers:', allSigners.data.length);

Managing Signer Permissions

// Get all signers
const signers = await listSigners('wallet-id');

// Update permissions for each signer
for (const signer of signers.data) {
  if (signer.type === 'EXTERNAL_WALLET') {
    // Limit external wallet to read-only
    await updateSignerPermissions('wallet-id', signer.publicKey, {
      permissions: {
        canSendSol: false,
        canSendTokens: false,
        canExecuteCpi: false
      }
    });
  } else if (signer.type === 'API_KEY') {
    // Full access for API key signer
    await updateSignerPermissions('wallet-id', signer.publicKey, {
      permissions: {
        canSendSol: true,
        canSendTokens: true,
        canExecuteCpi: true
      }
    });
  }
}

Signer Lifecycle Management

// Deactivate a signer temporarily
await updateSigner('wallet-id', 'signer-id', {
  isActive: false
});

// Reactivate later
await updateSigner('wallet-id', 'signer-id', {
  isActive: true
});

// Set primary signer
await updateSigner('wallet-id', 'signer-id', {
  isPrimary: true
});

// Remove signer when no longer needed
await deleteSigner('wallet-id', 'signer-id');

Signer Types

TypeDescriptionCustodyUse Case
EmailEmail-based authenticationNon-custodialWeb applications, email recovery
PhoneSMS-based authenticationNon-custodialMobile apps, phone verification
PasskeyWebAuthn/FIDO2 passkeysNon-custodialModern web auth, biometric
External WalletExternal wallet (Phantom, etc.)Non-custodialExisting wallet users
API KeyPlatform-managed keysCustodialServer-side operations

Best Practices

Always Set Up Recovery

Add multiple signers (email + phone) for account recovery

Use Appropriate Permissions

Set granular permissions based on signer trust level

Monitor Signer Status

Regularly check signer status and activity

Keep Signers Active

Maintain at least one active signer at all times

Signers Module | Cilantro Smart Wallet Docs | Cilantro Smart Wallet