ERC-4361 Sign-In with Ethereum (SIWE) (Sign-In with Ethereum)
Final · Signatures & auth · created 2021-10-11
Defines a standard message format and verification procedure for logging in to off-chain services such as websites with an Ethereum account. A session can be created with only a wallet signature, without a central login provider.
Why it is needed
Today, logging in to an ordinary web service goes through a centralized identity provider (IdP), such as a large internet company or an email provider. These providers ultimately control the user's identifier, and their interests can diverge from the user's. On the Ethereum side, many services already authenticate accounts with message signatures and create cookie-based sessions, but the message formats differ between services and are not compatible with one another. Wallets also could not tell which signature requests were for login, so it was hard for them to show a clear screen. It was also hard to filter out phishing requests where the site that sent the request differs from the site written in the message. This standard solves these problems by fixing a single format for the login message and a single verification procedure for both sides.
In depth
Message format: first line and required fields
The message must conform to the ABNF grammar of RFC 5234. The first line consists of an optional `scheme://`, then the `domain`, then the phrase ` wants you to sign in with your Ethereum account:`. The next line is the `address` (0x followed by 40 hex characters, with ERC-55 checksum casing recommended for EOAs), then a blank line, an optional `statement`, and a blank line. After that, the five lines `URI: `, `Version: `, `Chain ID: `, `Nonce: `, and `Issued At: ` are required and their order is fixed. In this specification `version` must be `1`. `chain-id` is the EIP-155 chain ID the session is bound to and also the network where the contract account is looked up. `nonce` must be at least 8 alphanumeric characters, and date fields use the RFC 3339 format. String items are case-sensitive, so writing `Chain ID` as `chain id` violates the format.
Optional fields: expiration, validity start, request ID, resources
After the five required lines, the following can be appended in order: `Expiration Time: ` (expiration time), `Not Before: ` (invalid before this time), `Request ID: ` (a system-specific request identifier), and `Resources:` (a list of URIs for information the user wants verified together during authentication). Each resource must be an RFC 3986 URI and is listed one per line, starting with `- ` after a line break. If `scheme` is omitted, it is assumed to be HTTPS. `domain` is an RFC 3986 authority, so it may include a port such as `example.com:3388`. If there is no port, the scheme's default port (443 for HTTPS) is assumed. `statement` is a human-readable ASCII sentence and must not contain a newline character (0x0a). How to interpret `resources` is outside the scope of this specification.
Signing method: ERC-191 for EOAs, ERC-1271 for contract accounts
The relying party requests a signature by prefixing the message with `\x19Ethereum Signed Message:\n<message length>` (ERC-191). An externally owned account (EOA) must use the ERC-191 verification method. For contract accounts, ERC-1271 verification is recommended, and if another method is used, the implementer must define it clearly. When verifying with ERC-1271, the verifying contract must be looked up on the chain that the message's `chain-id` points to. An ERC-1271 implementation need not be a pure function, so the same input can produce different results depending on chain state. The original gives as an example receiving state-change notifications (webhooks) and invalidating the related sessions. ERC-191 was chosen over EIP-712 because wallet support is already broad, implementation is simple since only a prefix is needed, and it produces a human-readable message.
Server implementation: specifying the origin, verification, sessions
`domain` and `scheme` must match the origin where the signature request actually occurred. If the request is made from inside a cross-origin iframe, the origin of the iframe, not the parent window, must be used so that the iframe cannot impersonate the top-level window. When a signed message is received, the server must confirm ABNF compliance, check that parsed values such as `expiration-time` and `nonce` match the expected values, and then verify the signature. The session must be bound to the `address`. It must not be bound to derived data that can change later, such as an ENS name. The URIs in `resources` are recommended to be in a form that is easy for people to read when shown as plain text. Before signing, the wallet may ask the server for an appropriate `nonce` or `resources`, but measures to minimize exposure of user information are recommended in that exchange.
Wallet implementation: blocking phishing through origin verification
The wallet must check that the whole message conforms to the ABNF. For an ERC-191 signature request that contains the phrase `wants you to sign in with your Ethereum account` but does not fully conform to the format, warning the user is recommended. The core of the check is comparing the request origin with the message's `scheme` and `domain`. In the recommended algorithm, if `scheme` is absent a default is filled in (https for browser wallets), and if the scheme is not on the allowlist the request must be rejected. If the scheme differs from the origin, reject (recommended); if the host of `domain` differs from the origin, it must be rejected; if the subdomain differs, reject (recommended). If the port differs, show a warning. In developer mode (for example, when the origin is localhost), rejection can be relaxed to a warning. The origin must be read from a trusted source such as the browser window or a WalletConnect (ERC-1328) session.
Wallet screen: fields that must be shown
Before signing, the wallet must display by default `scheme`, `domain`, `address`, `statement`, and `resources` if present. The other fields must also be viewable before signing, on the default screen or an expanded screen. A wallet that shows the plain-text message as is is recommended to let the user sign only after scrolling to the end of the text area. A wallet may also parse the ABNF items and build a dedicated screen, and the display rules above still apply in that case. After parsing is done, translation into each language can be handled at the UX stage. The relying party or wallet may additionally look up and show the ENS primary name (EIP-181), an avatar, and so on. However, the address may be passed to a third-party service during the lookup, so measures to protect user privacy and consent are recommended.
Out-of-scope items and backwards compatibility
This version does not cover authentication not based on an Ethereum address, authorization for server resources, interpretation of `resources` URIs, concrete methods for domain binding and nonce generation, or protocols without TLS. It leaves open as future work decentralized identifiers (DIDs) and verifiable credentials, cross-chain use, SIOPv2, EIP-712 support, and version interpretation rules. JWT was not used because wallets do not support it and the keccak hash is not registered as an IANA JOSE algorithm. ABNF was used instead of YAML because it can strictly define the character set, order, and whitespace. Most wallets already support ERC-191, so it is easy to move up from existing signature-based login. Requirements such as the terms-of-service consent phrase, nonce, and address inclusion were gathered from existing implementations. The status is Final.
Things to watch out for
- Identifier reuse and privacy: Signing in to several services with the same address links your activity across them. The original text says the ideal is to use a new identifier for each interaction and disclose only the necessary information selectively. Methods such as HD wallets, signing delegation, and zero-knowledge proofs are left as work for follow-up specifications.
- Key management: There is no forgot-password button from a central identity provider. If you lose your key there is no way to recover it, so this is a new responsibility for ordinary users. Smart contract and multisig wallets can improve the key usage and recovery experience through ERC-1271 signatures.
- Replay attack prevention: To stop an attacker from intercepting a user's signature and resending it to create their own session, the `nonce` must be chosen with sufficient entropy at the start of each session. A privacy-preserving nonce derived from a recent block hash or a Unix timestamp can also be considered.
- Phishing and channel security: If a wallet does not implement verification of the request origin, users are exposed to phishing. The protection is effective only when both the wallet and the service implement it. When connecting via QR code or deep link, users must be guided to check the domain of the TLS-protected site themselves. HTTPS is recommended for all web app communication.
- Session invalidation and maximum length: If the ERC-1271 implementation or data that affects signature computation changes, or if a resource listed in `resources` changes, the server must invalidate the related sessions. The specification does not set a maximum length for each field, so implementers must set length limits that balance denial-of-service protection against readability.