Sign-In with Ethereum (SIWE)
When apps need a confirmed sign-in (and not just a connect), they use Sign-In with Ethereum, or SIWE for short (EIP-4361). SIWE is a simple iteration on top of Personal Signatures with a standardized format allowing for easy parsing and verification.
The message encodes a chain identifier, uri, nonce, and issued at timestamp. It may also contain a statement provided by the app. All fields however are encoded in a human readable format and can easily be read by the user.
A complete message looks like this:
wallet.page wants you to sign in with your Ethereum account:
0xAb5801a7D9995314f5b2eA6574aB3F4D2eA09332
Sign in to wallet.page demos.
URI: https://wallet.page
Version: 1
Chain ID: 1
Nonce: a1b2c3d4e5f67890
Issued At: 2026-05-30T12:00:00.000ZImplement it
Build the string with a helper so you do not get the newlines wrong.
import { createSiweMessage, generateSiweNonce } from "viem/siwe";
const message = createSiweMessage({
domain: window.location.host,
address,
statement: "Sign in to My Dapp.",
uri: window.location.origin,
version: "1",
chainId: 1,
nonce: generateSiweNonce(),
});
await provider.request({
method: "personal_sign",
params: [message, address],
});import { SiweMessage } from "siwe";
const siwe = new SiweMessage({
domain: window.location.host,
address,
statement: "Sign in to My Dapp.",
uri: window.location.origin,
version: "1",
chainId: 1,
nonce: "a1b2c3d4e5f67890",
});
const message = siwe.prepareMessage();
await signer.signMessage(message);On the server, verify with verifySiweMessage (viem) or SiweMessage.verify (siwe). In the wallet UI, parse with parseSiweMessage from viem/siwe before you render.