Signers
Understanding signer types, authentication methods, and access control
Signers
Signers are authentication mechanisms that authorize transactions for a wallet. Each wallet can have multiple signers with different authentication methods and permissions.
Understanding Signers
Admin Signer - The Primary Controller
The admin signer is the first and most powerful signer added during wallet creation:
- Full Control: Can add/remove other signers
- Transaction Authority: Can authorize any transaction
- Wallet Configuration: Can update wallet settings
- Transfer Ownership: Can change admin to a different signer
If you create a user-controlled wallet, the admin signer determines who truly owns the wallet. Choose carefully!
Signer Lifecycle
- Creation: Add a signer to a wallet
- Registration: Register on-chain (automatic for most types)
- Usage: Sign transactions
- Management: Update permissions, deactivate, or remove
Signer Types Overview
| Type | Description | Use Case | Custody |
|---|---|---|---|
| Email-based authentication with device keys | Web applications, email recovery | Non-custodial | |
| Phone | SMS-based authentication with device keys | Mobile apps, phone verification | Non-custodial |
| Passkey | WebAuthn/FIDO2 passkeys | Modern web auth, biometric | Non-custodial |
| External | External wallet (Phantom, Solflare, etc.) | Existing wallet users | Non-custodial |
| API Key | Platform-managed keys | Server-side operations | Custodial |
1. Email Signer (Non-Custodial)
User authenticates with email while maintaining control of their keys through device key encryption.
How It Works
- Device Key Generation: Client generates P-256 ECDH keypair on their device
- Server Encryption: Server encrypts master secret using ECDH shared secret
- Key Derivation: Client derives Ed25519 signing keys from master secret
- Transaction Signing: All signing happens client-side
Security Properties:
- ✅ Platform never sees device private key
- ✅ Platform never sees signing private key
- ✅ User can access wallet from multiple devices
- ✅ Lost device? Just add a new device key
Using Helper (Recommended - Automatic)
import {
createEmailSignerHelper,
getEmailSignerKeypair,
createIndexedDBAdapter
} from 'cilantro-sdk/helpers';
// Step 1: Create storage adapter (use IndexedDB in browser)
const storage = createIndexedDBAdapter();
// Step 2: Create email signer (device key generated automatically)
const signer = await createEmailSignerHelper('wallet-id', {
email: 'user@example.com',
deviceKeyManager: storage
});
console.log('Email signer created:', signer.signerId);
// Step 3: Get keypair for signing (with caching)
const keypair = await getEmailSignerKeypair(
'wallet-id',
signer.signerId,
{ deviceKeyManager: storage }
);
console.log('Keypair ready for signing');
Manual Approach
import { createEmailSigner } from 'cilantro-sdk/wallet';
import { generateDeviceKeyPair } from 'cilantro-sdk/helpers';
// Step 1: Generate device key
const deviceKey = await generateDeviceKeyPair();
// Step 2: Create email signer
await createEmailSigner('wallet-id', {
email: 'user@example.com',
devicePublicKey: deviceKey.publicKey
});
// Step 3: Store device key securely for later use
// Must store deviceKey.privateKey, deviceKey.publicKey, deviceKey.keyId
Best For:
- Web applications with social login
- Email-based account recovery
- First-time crypto users
- Multi-device access scenarios
2. Phone Signer (Non-Custodial)
Similar to email signer but uses phone number authentication.
import {
createPhoneSignerHelper,
getPhoneSignerKeypair,
createIndexedDBAdapter
} from 'cilantro-sdk/helpers';
const storage = createIndexedDBAdapter();
// Create phone signer
const signer = await createPhoneSignerHelper('wallet-id', {
phone: '+1234567890',
deviceKeyManager: storage
});
// Get keypair for signing
const keypair = await getPhoneSignerKeypair(
'wallet-id',
signer.signerId,
{ deviceKeyManager: storage }
);
Best For:
- Mobile-first applications
- SMS-based verification
- Regions where phone verification is preferred
- Secondary authentication method
3. Passkey Signer (Most Secure)
WebAuthn/FIDO2 hardware keys or biometrics. Private keys are stored in device secure enclave or hardware security module.
import {
startPasskeyRegistration,
verifyPasskeyRegistration
} from 'cilantro-sdk/wallet';
// Step 1: Start registration
const registrationOptions = await startPasskeyRegistration('wallet-id');
// Step 2: Get credential from browser
const credential = await navigator.credentials.create({
publicKey: registrationOptions.data
});
// Step 3: Verify and register
await verifyPasskeyRegistration('wallet-id', {
response: credential.response,
credentialId: credential.id
});
console.log('Passkey signer registered');
Security Features:
- 🔒 Private key stored in hardware secure enclave
- 🔒 Biometric authentication (Face ID, Touch ID, Windows Hello)
- 🔒 Phishing-resistant (origin-bound)
- 🔒 No password to remember or steal
Best For:
- High-value transactions
- Security-conscious users
- Modern web applications
- Passwordless authentication
4. External Wallet Signer
For users with existing Solana wallets (Phantom, Solflare, Backpack, etc.).
import { createExternalWalletSigner } from 'cilantro-sdk/wallet';
// User connects their wallet (e.g., Phantom)
const connectedPublicKey = 'DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK';
await createExternalWalletSigner('wallet-id', {
publicKey: connectedPublicKey,
signerName: 'Phantom Wallet', // Optional
chain: 'solana'
});
console.log('External wallet registered as signer');
How It Works:
- User connects existing wallet via browser extension
- Cilantro registers wallet's public key as signer
- For transactions, Cilantro prepares TX and requests signature
- User signs in their wallet, Cilantro submits
Best For:
- Experienced crypto users
- Users who already have a Solana wallet
- Wallet aggregation platforms
- dApp integrations
5. API Key Signer (Custodial)
For platform-controlled signing. Platform has full custody of the keys.
import { createApiKeySigner } from 'cilantro-sdk/wallet';
await createApiKeySigner('wallet-id', {
apiKeyName: 'Server Signer',
permissions: {
canTransfer: true,
maxAmount: 1000000000 // 1 SOL in lamports
}
});
Best For:
- Gaming rewards and in-game currency
- Automated operations and batch processing
- Fiat on-ramps
- Server-side transaction signing
- Platform treasury management
API Key Signers are custodial - the platform controls the private keys. Use only when appropriate for your use case.
Custody Comparison
Platform-Controlled (Custodial)
Platform has signing keys
Pros:
- Simple UX, no user key management
- Instant transactions
- Easy batch operations
Cons:
- Platform can access funds
- Regulatory implications
- Single point of failure
Use case: Gaming credits, reward points, managed accounts
User-Controlled (Non-Custodial)
User has keys via device encryption
Keys derived from device keys, platform never sees private keys
Keys in secure hardware
Most secure option, keys never leave device secure enclave
Keys in user's wallet
User retains control through existing wallet software
Multi-Signer Wallets
Wallets can have multiple signers for enhanced security and flexibility:
import { create } from 'cilantro-sdk/wallet';
import {
createEmailSignerHelper,
createPhoneSignerHelper
} from 'cilantro-sdk/helpers';
// Create wallet
const { data } = await create({ name: 'Multi-Signer Wallet', userId: 'user-id' });
const walletId = data.id;
const storage = createIndexedDBAdapter(); // or createLocalStorageAdapter()
// Add email signer (primary)
await createEmailSignerHelper(walletId, {
email: 'user@example.com',
deviceKeyManager: storage
});
// Add phone signer (recovery)
await createPhoneSignerHelper(walletId, {
phone: '+1234567890',
deviceKeyManager: storage
});
// Add passkey signer (high-value transactions)
const passkeyOptions = await startPasskeyRegistration(walletId);
// ... complete passkey registration
Use Cases:
- Multi-factor authentication: Require multiple signers for sensitive operations
- Social Recovery: Email + phone for account recovery
- Shared Wallets: Multiple users can sign transactions (treasury, family wallet)
- Tiered Security: Different signers for different transaction amounts
Managing Signers
List All Signers
import { listSigners } from 'cilantro-sdk/wallet';
const signers = await listSigners('wallet-id');
console.log('Wallet signers:', signers.data);
Get Signer Details
import { getSignerById } from 'cilantro-sdk/wallet';
const signer = await getSignerById('wallet-id', 'signer-id');
console.log('Signer details:', signer.data);
Update Signer Status
import { updateSigner } from 'cilantro-sdk/wallet';
await updateSigner('wallet-id', 'signer-id', {
active: true,
primary: false
});
Remove Signer
import { deleteSigner } from 'cilantro-sdk/wallet';
await deleteSigner('wallet-id', 'signer-id');
Be careful when removing signers. Make sure you have alternative access methods before removing a signer!
Signer Permissions
Control what each signer can do with granular permissions:
import { updateSignerPermissions } from 'cilantro-sdk/wallet';
// Read-only signer (can view but not transact)
await updateSignerPermissions('wallet-id', 'signer-public-key', {
permissions: []
});
// Transfer-only signer
await updateSignerPermissions('wallet-id', 'signer-public-key', {
permissions: ['send'],
maxAmount: 1000000000 // 1 SOL limit
});
// Full access signer
await updateSignerPermissions('wallet-id', 'signer-public-key', {
permissions: ['send', 'mint', 'burn', 'admin']
});
Best Practices
Security Considerations
- Store device keys securely (encrypted storage)
- Implement key rotation policies
- Use secure enclaves when available
- Back up device keys safely
- Educate users about key security
- Store keys in HSM or cloud KMS
- Implement multi-signature for large amounts
- Monitor and alert on suspicious activity
- Maintain audit logs
- Have incident response plan