Signer Management

Comprehensive guide to managing wallet signers and authentication methods

Signer Management Guide

This guide covers comprehensive signer management including creating different signer types, managing permissions, multi-signer patterns, and signer recovery.

Understanding Signers

Signers are authentication mechanisms that authorize transactions for a wallet. Each wallet can have multiple signers with different authentication methods and permissions.

Signer Types Overview

TypeCustodyUse CaseSecurity Level
EmailNon-custodialWeb applications, email recoveryMedium
PhoneNon-custodialMobile apps, phone verificationMedium
PasskeyNon-custodialModern web auth, biometricHigh
External WalletNon-custodialExisting wallet usersHigh
API KeyCustodialServer-side operationsMedium

Creating Signers

Email Signer

Email signers use email-based authentication with device keys for non-custodial control.

import { createEmailSignerHelper } from 'cilantro-sdk/helpers';
import { createLocalStorageAdapter } from 'cilantro-sdk/helpers';

const storage = createLocalStorageAdapter();

const signer = await createEmailSignerHelper('wallet-id', {
  email: 'user@example.com',
  deviceKeyManager: storage
});

console.log('Email signer created:', signer.signerId);

Phone Signer

Phone signers use SMS-based authentication with device keys.

import { createPhoneSignerHelper } from 'cilantro-sdk/helpers';

const signer = await createPhoneSignerHelper('wallet-id', {
  phone: '+1234567890',
  deviceKeyManager: storage
});

console.log('Phone signer created:', signer.signerId);

Passkey Signer

Passkey signers use WebAuthn/FIDO2 for hardware-backed authentication.

import { startPasskeyRegistration, verifyPasskeyRegistration } from 'cilantro-sdk/wallet';

// Step 1: Start registration
const options = await startPasskeyRegistration('wallet-id');

// Step 2: Create credential
const credential = await navigator.credentials.create({
  publicKey: options.data
});

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

External Wallet Signer

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

import { createExternalWalletSigner } from 'cilantro-sdk/signers';

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

API Key Signer

Create a custodial API key signer for server-side operations.

import { createApiKeySigner } from 'cilantro-sdk/signers';

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

Managing Signer Permissions

Read-Only Signer

Create a signer that can only view wallet information.

import { updateSignerPermissions } from 'cilantro-sdk/signers';

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

Limited Transfer Signer

Create a signer with transfer limits.

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

Program-Specific Signer

Restrict signer to specific programs.

await updateSignerPermissions('wallet-id', 'signer-public-key', {
  permissions: {
    canSendSol: false,
    canSendTokens: false,
    canExecuteCpi: true,
    allowedPrograms: [
      'program-id-1',
      'program-id-2'
    ]
  }
});

Full Access Signer

Grant complete permissions to a signer.

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

Multi-Signer Patterns

Primary + Recovery Pattern

Set up a primary signer with recovery options.

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

// Add primary email signer
const primary = await createEmailSignerHelper(wallet.data.walletId, {
  email: 'user@example.com',
  deviceKeyManager: storage
});

// Add phone signer as recovery
const recovery = await createPhoneSignerHelper(wallet.data.walletId, {
  phone: '+1234567890',
  deviceKeyManager: storage
});

// Set primary signer
await updateSigner(wallet.data.walletId, primary.signerId, {
  isPrimary: true
});

Multi-Factor Authentication

Require multiple signers for sensitive operations.

// Add email signer
const emailSigner = await createEmailSignerHelper(walletId, {
  email: 'user@example.com',
  deviceKeyManager: storage
});

// Add passkey signer for high-value transactions
const passkeySigner = await registerPasskey(walletId);

// Both signers must approve high-value transactions
// (Implementation depends on your wallet's multi-sig configuration)

Shared Wallet Pattern

Multiple users can sign transactions.

// User 1's signer
const user1Signer = await createEmailSignerHelper(walletId, {
  email: 'user1@example.com',
  deviceKeyManager: storage1
});

// User 2's signer
const user2Signer = await createEmailSignerHelper(walletId, {
  email: 'user2@example.com',
  deviceKeyManager: storage2
});

// User 3's signer
const user3Signer = await createEmailSignerHelper(walletId, {
  email: 'user3@example.com',
  deviceKeyManager: storage3
});

// Configure for 2-of-3 multi-sig
// (Requires wallet program configuration)

Signer Lifecycle Management

Listing Signers

import { listSigners } from 'cilantro-sdk/signers';

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

console.log('Total signers:', signers.data.length);
signers.data.forEach(signer => {
  console.log(`- ${signer.type}: ${signer.isActive ? 'Active' : 'Inactive'}`);
});

Getting Signer Details

import { getSignerById } from 'cilantro-sdk/signers';

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

Updating Signer Status

import { updateSigner } from 'cilantro-sdk/signers';

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

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

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

Removing Signers

import { deleteSigner } from 'cilantro-sdk/signers';

// Remove a signer
await deleteSigner('wallet-id', 'signer-id');

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

Signer Recovery

Device Recovery for Email/Phone Signers

import { 
  addNewDeviceToSigner,
  replaceDeviceIdentity 
} from 'cilantro-sdk/helpers';

// Add a new device to existing signer
const newDeviceKey = await generateDeviceKeyPair();
await addNewDeviceToSigner('wallet-id', 'signer-id', {
  deviceKeyManager: storage
});

// Replace old device
await replaceDeviceIdentity('wallet-id', 'signer-id', {
  oldDeviceId: 'old-device-id',
  newIdentity: {
    devicePublicKey: newDeviceKey.publicKey,
    deviceId: 'new-device-id'
  }
});

Passkey Recovery

// Register a backup passkey
const backupPasskey = await registerPasskey('wallet-id');

// If primary passkey is lost, use backup
const authResult = await authenticateWithPasskey('wallet-id', backupPasskey.credentialId);

Best Practices

Security

Multiple Recovery Methods

Always set up multiple signers (email + phone) for account recovery

Least Privilege

Grant minimum necessary permissions to each signer

Regular Audits

Regularly review and audit signer permissions

Backup Signers

Maintain backup signers in case primary is lost

Organization

// Organize signers by purpose
async function organizeSigners(walletId: string) {
  const signers = await listSigners(walletId);
  
  const primary = signers.data.find(s => s.isPrimary);
  const recovery = signers.data.filter(s => s.type === 'PHONE' || s.type === 'EMAIL');
  const highSecurity = signers.data.filter(s => s.type === 'PASSKEY');
  const external = signers.data.filter(s => s.type === 'EXTERNAL_WALLET');
  const apiKeys = signers.data.filter(s => s.type === 'API_KEY');
  
  return {
    primary,
    recovery,
    highSecurity,
    external,
    apiKeys
  };
}

Common Patterns

Tiered Security

// Low-value: Email signer
const emailSigner = await createEmailSignerHelper(walletId, {
  email: 'user@example.com',
  deviceKeyManager: storage
});

// Medium-value: Phone signer
const phoneSigner = await createPhoneSignerHelper(walletId, {
  phone: '+1234567890',
  deviceKeyManager: storage
});

// High-value: Passkey signer
const passkeySigner = await registerPasskey(walletId);

// Configure permissions based on value
await updateSignerPermissions(walletId, emailSigner.publicKey, {
  permissions: {
    canSendSol: true,
    maxTransferAmount: 1000000000 // 1 SOL limit
  }
});

await updateSignerPermissions(walletId, passkeySigner.publicKey, {
  permissions: {
    canSendSol: true,
    canSendTokens: true,
    canExecuteCpi: true
    // No limit for high-security signer
  }
});

Automated Operations

// Use API key signer for automated operations
const apiKeySigner = await createApiKeySigner(walletId, {
  apiKeyName: 'Automated Bot'
});

// Configure for specific operations only
await updateSignerPermissions(walletId, apiKeySigner.publicKey, {
  permissions: {
    canSendSol: true,
    canSendTokens: false,
    canExecuteCpi: true,
    allowedPrograms: ['specific-program-id']
  }
});

Next Steps

Signer Management | Cilantro Smart Wallet Docs | Cilantro Smart Wallet