Разработка авторизации через кошелёк (Sign-In with Ethereum)
Sign-In with Ethereum (SIWE, EIP-4361) — стандарт аутентификации где пользователь подписывает сообщение своим Ethereum кошельком для входа в dApp. Никаких паролей, никаких email — только криптографическая подпись. Это wallet-based auth, ставший стандартом в Web3.
Как работает SIWE
- Backend генерирует message с nonce
- Frontend показывает message пользователю для подписания
- Пользователь подписывает через MetaMask/WalletConnect
- Backend верифицирует подпись → извлекает адрес → создаёт сессию
Стандартный SIWE message format:
app.example.com wants you to sign in with your Ethereum account:
0xYourAddress
Sign in to Example App
URI: https://app.example.com
Version: 1
Chain ID: 1
Nonce: abc123def456
Issued At: 2024-01-15T10:30:00.000Z
Expiration Time: 2024-01-15T11:30:00.000Z
Реализация на бэкенде (Node.js)
import { SiweMessage, generateNonce } from 'siwe';
import { ethers } from 'ethers';
// 1. Генерация nonce
app.get('/api/nonce', (req, res) => {
const nonce = generateNonce();
req.session.nonce = nonce;
res.json({ nonce });
});
// 2. Верификация подписи
app.post('/api/verify', async (req, res) => {
const { message, signature } = req.body;
const siweMessage = new SiweMessage(message);
try {
const fields = await siweMessage.verify({
signature,
nonce: req.session.nonce,
domain: 'app.example.com'
});
// Подпись верна — пользователь владеет этим адресом
req.session.user = {
address: fields.data.address,
chainId: fields.data.chainId
};
res.json({ success: true, address: fields.data.address });
} catch (error) {
res.status(401).json({ error: 'Invalid signature' });
}
});
Frontend реализация с wagmi
import { useSignMessage, useAccount } from 'wagmi';
import { SiweMessage } from 'siwe';
function SignInButton() {
const { address } = useAccount();
const { signMessageAsync } = useSignMessage();
const handleSignIn = async () => {
// Получить nonce от backend
const { nonce } = await fetch('/api/nonce').then(r => r.json());
// Сформировать SIWE message
const message = new SiweMessage({
domain: window.location.host,
address,
statement: 'Sign in to Example App',
uri: window.location.origin,
version: '1',
chainId: 1,
nonce,
});
// Подписать
const signature = await signMessageAsync({
message: message.prepareMessage()
});
// Верифицировать на backend
await fetch('/api/verify', {
method: 'POST',
body: JSON.stringify({ message: message.prepareMessage(), signature })
});
};
return <button onClick={handleSignIn}>Sign In with Ethereum</button>;
}
Защита от атак
Replay attacks: каждый nonce используется один раз. Backend инвалидирует nonce после верификации.
Phishing: message должен содержать правильный domain. Пользователь подписывает именно для вашего домена, не для другого.
Session management: после SIWE создаётся обычная HTTP сессия (JWT, session cookie). SIWE — только для начального auth, не для каждого запроса.
SIWE — золотой стандарт Web3 auth. Интеграция с existing backend — 1-3 дня.







