patternjavascriptTip
Decentralized identity: Sign-In with Ethereum (SIWE) implementation
Viewed 0 times
siwe 2.x
SIWESign-In with EthereumEIP-4361authenticationnoncewallet login
Error Messages
Problem
You want users to authenticate with their Ethereum wallet instead of a username/password, using a standardized sign-in flow.
Solution
Use the siwe library to create, parse, and verify EIP-4361 messages. Generate a nonce server-side, have the user sign the SIWE message, then verify server-side.
import { SiweMessage } from 'siwe';
const message = new SiweMessage({ domain, address, statement, uri, version: '1', chainId, nonce });
const signature = await signer.signMessage(message.prepareMessage());
await message.verify({ signature });Why
EIP-4361 (SIWE) is a standard that makes wallet-based authentication consistent across apps, prevents replay attacks with nonces, and is recognized by major wallet UIs with clear signing prompts.
Gotchas
- Always generate the nonce server-side and verify it matches to prevent replay attacks
- The domain in the SIWE message must match window.location.host — wallets display a warning if they differ
- SIWE does not create a persistent session on its own — issue a JWT or session cookie after successful verification
Code Snippets
Full SIWE authentication flow
import { SiweMessage, generateNonce } from 'siwe';
// Server: generate nonce
app.get('/nonce', (req, res) => {
req.session.nonce = generateNonce();
res.json({ nonce: req.session.nonce });
});
// Client: sign
async function signIn(signer, nonce) {
const address = await signer.getAddress();
const message = new SiweMessage({
domain: window.location.host,
address,
statement: 'Sign in to My App',
uri: window.location.origin,
version: '1',
chainId: 1,
nonce,
});
const signature = await signer.signMessage(message.prepareMessage());
return { message: message.prepareMessage(), signature };
}
// Server: verify
app.post('/verify', async (req, res) => {
const { message, signature } = req.body;
const siweMessage = new SiweMessage(message);
const { data } = await siweMessage.verify({ signature, nonce: req.session.nonce });
req.session.address = data.address;
res.json({ ok: true });
});Context
Building dApps with wallet-based user authentication
Revisions (0)
No revisions yet.