Blockchain Integration
SirrChat's blockchain integration enables passwordless authentication using EVM wallet signatures. This innovative approach eliminates traditional password vulnerabilities while providing cryptographically secure access control.
Overview
The blockchain authentication module (auth.pass_blockchain) allows users to authenticate using their Ethereum (or EVM-compatible) wallet signatures instead of traditional passwords.
How It Works
- User Registration: User's wallet address is registered with the email account
- Authentication Request: Client signs a challenge message with their private key
- Signature Verification: Server recovers the public key from the signature
- Access Grant: If the recovered address matches the registered address, access is granted
Configuration
Basic Setup
Add blockchain authentication to your sirrchatd.conf:
# Blockchain configuration
blockchain sirrchatd {
rpc_endpoint https://mainnet.infura.io/v3/YOUR_PROJECT_ID
chain_id 1 # Ethereum Mainnet
}
# Authentication module
auth.pass_blockchain blockchain_auth {
blockchain &sirrchatd
storage &local_mailboxes
}
# Use in IMAP endpoint
imap tls://0.0.0.0:993 {
auth &blockchain_auth
storage &local_mailboxes
}Supported Chains
SirrChat supports any EVM-compatible blockchain:
| Chain | Chain ID | Network |
|---|---|---|
| Ethereum Mainnet | 1 | Production |
| Ethereum Goerli | 5 | Testnet |
| Ethereum Sepolia | 11155111 | Testnet |
| BSC Mainnet | 56 | Production |
| BSC Testnet | 97 | Testnet |
| Polygon Mainnet | 137 | Production |
| Polygon Mumbai | 80001 | Testnet |
| Arbitrum One | 42161 | Production |
| Optimism | 10 | Production |
Authentication Flow
1. Challenge Generation
When a user attempts to authenticate, the server generates a challenge message:
Challenge: <random_nonce>
Timestamp: <unix_timestamp>
Service: sirrchat2. Client-Side Signing
The client signs the challenge using their Ethereum wallet:
// Example using ethers.js
const message = `Challenge: ${nonce}\nTimestamp: ${timestamp}\nService: sirrchat`;
const signature = await wallet.signMessage(message);3. Server-Side Verification
The server verifies the signature and recovers the address:
// Internal verification process
func (bc *Ethereum) CheckSign(ctx context.Context, pk, sign, message string) (bool, error) {
hash := crypto.Keccak256Hash([]byte(message))
signature := hexutil.MustDecode(sign)
// Recover public key from signature
pubKey, err := crypto.SigToPub(hash.Bytes(), signature)
if err != nil {
return false, err
}
// Get address from public key
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
// Compare with registered address
return recoveredAddr.Hex() == pk, nil
}User Management
Register Blockchain User
# Register a wallet address with an email account
sirrchatd creds create-blockchain \
--email [email protected] \
--address 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
# List blockchain users
sirrchatd creds list-blockchainUpdate Wallet Address
# Update wallet address for an existing account
sirrchatd creds update-blockchain \
--email [email protected] \
--address 0xNewAddressRemove Blockchain Authentication
# Remove blockchain auth (keep email account)
sirrchatd creds remove-blockchain --email [email protected]Client Implementation
Email Client Configuration
Configure your email client to use blockchain authentication:
IMAP Settings:
- Server: your-domain.com
- Port: 993
- Security: SSL/TLS
- Username: [email protected]
- Password:
<signature>(the wallet signature)
Custom Client Example
Here's a simple example of implementing blockchain auth in a custom client:
const ethers = require('ethers');
class BlockchainEmailAuth {
constructor(walletAddress, privateKey) {
this.wallet = new ethers.Wallet(privateKey);
this.address = walletAddress;
}
async generateAuthCredentials(challenge, timestamp) {
const message = `Challenge: ${challenge}\nTimestamp: ${timestamp}\nService: sirrchat`;
const signature = await this.wallet.signMessage(message);
return {
username: `[email protected]`,
password: signature,
address: this.address
};
}
async connectIMAP(host, port) {
// Get challenge from server
const { challenge, timestamp } = await this.getChallengeFromServer();
// Generate credentials
const creds = await this.generateAuthCredentials(challenge, timestamp);
// Connect to IMAP server
// ... use creds to authenticate
}
}Security Considerations
Best Practices
- Never Share Private Keys: Private keys should never be transmitted or stored on the server
- Use Hardware Wallets: For production use, consider hardware wallet integration
- Implement Nonce Expiry: Challenge nonces should expire after a short period
- Rate Limiting: Implement rate limiting on authentication attempts
- Audit Logging: Log all authentication attempts for security monitoring
Replay Attack Prevention
The server includes anti-replay protections:
auth.pass_blockchain blockchain_auth {
blockchain &sirrchatd
storage &local_mailboxes
# Challenge configuration
challenge_expiry 300s # 5 minutes
nonce_cache_size 10000
}Advantages Over Traditional Authentication
Security Benefits
- No Password Storage: Eliminates password database breaches
- Cryptographic Verification: Based on proven elliptic curve cryptography
- No Password Reuse: Each signature is unique
- Phishing Resistant: Cannot be tricked into revealing credentials
User Experience
- No Password Management: Users don't need to remember passwords
- Multi-Device: Same wallet can be used across all devices
- Recovery Options: Use wallet recovery mechanisms instead of password resets
Integration with Web3 Applications
DApp Integration
Integrate email functionality into your DApp:
// Example: Send email from DApp
async function sendEmailFromDApp(web3Provider) {
const signer = web3Provider.getSigner();
const address = await signer.getAddress();
// Get challenge
const challenge = await fetchChallenge();
// Sign challenge
const signature = await signer.signMessage(challenge.message);
// Authenticate and send email
await sendEmail({
from: `${address}@yourdomain.com`,
signature: signature,
to: '[email protected]',
subject: 'Hello from DApp',
body: 'This email was sent using blockchain authentication!'
});
}Troubleshooting
Common Issues
Signature Verification Fails
# Check if address is registered
sirrchatd creds list-blockchain | grep [email protected]
# Verify challenge format
# Ensure client and server use the same message formatRPC Connection Issues
# Test RPC endpoint
curl -X POST https://mainnet.infura.io/v3/YOUR_PROJECT_ID \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'Advanced Configuration
Multiple Chain Support
# Support multiple chains
blockchain eth_mainnet {
rpc_endpoint https://mainnet.infura.io/v3/YOUR_PROJECT_ID
chain_id 1
}
blockchain bsc_mainnet {
rpc_endpoint https://bsc-dataseed1.binance.org
chain_id 56
}
auth.pass_blockchain multi_chain_auth {
blockchain ð_mainnet &bsc_mainnet
storage &local_mailboxes
}Custom Verification Logic
Extend the blockchain module for custom verification:
// Custom verification implementation
type CustomBlockchainAuth struct {
baseAuth *blockchain.Ethereum
}
func (c *CustomBlockchainAuth) VerifyWithNFT(ctx context.Context, address, signature string) (bool, error) {
// Verify signature
valid, err := c.baseAuth.CheckSign(ctx, address, signature, message)
if err != nil || !valid {
return false, err
}
// Additional NFT ownership check
hasNFT, err := c.checkNFTOwnership(ctx, address)
return hasNFT, err
}API Reference
Core Interface
type BlockChain interface {
// Send raw transaction to blockchain
SendRawTx(ctx context.Context, rawTx string) error
// Get blockchain type
ChainType(ctx context.Context) string
// Verify signature and check if it matches public key
CheckSign(ctx context.Context, pk, sign, message string) (bool, error)
}Resources
Blockchain authentication eliminates passwords while enhancing security through cryptographic verification.