Sign-In with Ethereum describes how Ethereum accounts authenticate with off-chain services by signing a standard message format parameterized by scope, session details, and security mechanisms (e.g., a nonce). The goals of this specification are to provide a self-custodied alternative to centralized identity providers, improve interoperability across off-chain services for Ethereum-based authentication, and provide wallet vendors a consistent machine-readable message format to achieve improved user experiences and consent management.
When signing in to popular non-blockchain services today, users will typically use identity providers (IdPs) that are centralized entities with ultimate control over users' identifiers, for example, large internet companies and email providers. Incentives are often misaligned between these parties. Sign-In with Ethereum offers a new self-custodial option for users who wish to assume more control and responsibility over their own digital identity.
Already, many services support workflows to authenticate Ethereum accounts using message signing, such as to establish a cookie-based web session which can manage privileged metadata about the authenticating address. This is an opportunity to standardize the sign-in workflow and improve interoperability across existing services, while also providing wallet vendors a reliable method to identify signing requests as Sign-In with Ethereum requests for improved UX.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Sign-In with Ethereum (SIWE) works as follows:
\x19Ethereum Signed Message:\n<length of message>
as defined in ERC-191.A SIWE Message MUST conform with the following Augmented Backus–Naur Form (ABNF, RFC 5234) expression (note that %s
denotes case sensitivity for a string term, as per RFC 7405).
sign-in-with-ethereum =
[ scheme "://" ] domain %s" wants you to sign in with your Ethereum account:" LF
address LF
LF
[ statement LF ]
LF
%s"URI: " uri LF
%s"Version: " version LF
%s"Chain ID: " chain-id LF
%s"Nonce: " nonce LF
%s"Issued At: " issued-at
[ LF %s"Expiration Time: " expiration-time ]
[ LF %s"Not Before: " not-before ]
[ LF %s"Request ID: " request-id ]
[ LF %s"Resources:"
resources ]
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
; See RFC 3986 for the fully contextualized
; definition of "scheme".
domain = authority
; From RFC 3986:
; authority = [ userinfo "@" ] host [ ":" port ]
; See RFC 3986 for the fully contextualized
; definition of "authority".
address = "0x" 40*40HEXDIG
; Must also conform to capitalization
; checksum encoding specified in EIP-55
; where applicable (EOAs).
statement = *( reserved / unreserved / " " )
; See RFC 3986 for the definition
; of "reserved" and "unreserved".
; The purpose is to exclude LF (line break).
uri = URI
; See RFC 3986 for the definition of "URI".
version = "1"
chain-id = 1*DIGIT
; See EIP-155 for valid CHAIN_IDs.
nonce = 8*( ALPHA / DIGIT )
; See RFC 5234 for the definition
; of "ALPHA" and "DIGIT".
issued-at = date-time
expiration-time = date-time
not-before = date-time
; See RFC 3339 (ISO 8601) for the
; definition of "date-time".
request-id = *pchar
; See RFC 3986 for the definition of "pchar".
resources = *( LF resource )
resource = "- " URI
This specification defines the following SIWE Message fields that can be parsed from a SIWE Message by following the rules in ABNF Message Format:
scheme
OPTIONAL. The URI scheme of the origin of the request. Its value MUST be an RFC 3986 URI scheme.domain
REQUIRED. The domain that is requesting the signing. Its value MUST be an RFC 3986 authority. The authority includes an OPTIONAL port. If the port is not specified, the default port for the provided scheme
is assumed (e.g., 443 for HTTPS). If scheme
is not specified, HTTPS is assumed by default.address
REQUIRED. The Ethereum address performing the signing. Its value SHOULD be conformant to mixed-case checksum address encoding specified in ERC-55 where applicable.statement
OPTIONAL. A human-readable ASCII assertion that the user will sign which MUST NOT include '\n'
(the byte 0x0a
).uri
REQUIRED. An RFC 3986 URI referring to the resource that is the subject of the signing (as in the subject of a claim).version
REQUIRED. The current version of the SIWE Message, which MUST be 1
for this specification.chain-id
REQUIRED. The EIP-155 Chain ID to which the session is bound, and the network where Contract Accounts MUST be resolved.nonce
REQUIRED. A random string typically chosen by the relying party and used to prevent replay attacks, at least 8 alphanumeric characters.issued-at
REQUIRED. The time when the message was generated, typically the current time. Its value MUST be an ISO 8601 datetime string.expiration-time
OPTIONAL. The time when the signed authentication message is no longer valid. Its value MUST be an ISO 8601 datetime string.not-before
OPTIONAL. The time when the signed authentication message will become valid. Its value MUST be an ISO 8601 datetime string.request-id
OPTIONAL. A system-specific identifier that MAY be used to uniquely refer to the sign-in request.resources
OPTIONAL. A list of information or references to information the user wishes to have resolved as part of authentication by the relying party. Every resource MUST be an RFC 3986 URI separated by "\n- "
where \n
is the byte 0x0a
.A Bash-like informal template of the full SIWE Message is presented below for readability and ease of understanding, and it does not reflect the allowed optionality of the fields. Field descriptions are provided in the following section. A full ABNF description is provided in ABNF Message Format.
${scheme}:// ${domain} wants you to sign in with your Ethereum account:
${address}
${statement}
URI: ${uri}
Version: ${version}
Chain ID: ${chain-id}
Nonce: ${nonce}
Issued At: ${issued-at}
Expiration Time: ${expiration-time}
Not Before: ${not-before}
Request ID: ${request-id}
Resources:
- ${resources[0]}
- ${resources[1]}
...
- ${resources[n]}
The following is an example SIWE Message with an implicit scheme:
example.com wants you to sign in with your Ethereum account:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
I accept the ExampleOrg Terms of Service: https://example.com/tos
URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891756
Issued At: 2021-09-30T16:25:24Z
Resources:
- ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/
- https://example.com/my-web2-claim.json
The following is an example SIWE Message with an implicit scheme and explicit port:
example.com:3388 wants you to sign in with your Ethereum account:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
I accept the ExampleOrg Terms of Service: https://example.com/tos
URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891756
Issued At: 2021-09-30T16:25:24Z
Resources:
- ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/
- https://example.com/my-web2-claim.json
The following is an example SIWE Message with an explicit scheme:
https://example.com wants you to sign in with your Ethereum account:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
I accept the ExampleOrg Terms of Service: https://example.com/tos
URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891756
Issued At: 2021-09-30T16:25:24Z
Resources:
- ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/
- https://example.com/my-web2-claim.json
For Externally Owned Accounts (EOAs), the verification method specified in ERC-191 MUST be used.
For Contract Accounts,
chain-id
.address
. Resolvable ENS data include:address
could be forwarded to third party services as part of the resolution process.domain
and, if present, the scheme
, in the SIWE Message MUST correspond to the origin from where the signing request was made. For instance, if the signing request is made within a cross-origin iframe embedded in a parent browser window, the domain
(and, if present, the scheme
) have to match the origin of the iframe, rather than the origin of the parent. This is crucial to prevent the iframe from falsely asserting the origin of one of its ancestor windows for security reasons. This behavior is enforced by conforming wallets.expiration-time
, nonce
, request-uri
etc.), and its signature MUST be checked as defined in Signing and Verifying Messages with Ethereum Accounts.address
and not to further resolved resources that can change.resources
are human-friendly when expressed in plaintext form.resources
in the SIWE Message is out of scope of this specification."wants you to sign in
with your Ethereum account"
appears anywhere in an ERC-191 message signing
request unless the message fully conforms to the format defined ABNF Message Format.scheme
and domain
fields in the SIWE Message. For example, when processing the SIWE message beginning with "example.com wants you to sign in..."
, the wallet checks that the request actually originated from https://example.com
.The following is a RECOMMENDED algorithm for Wallets to conform with the requirements on request origin verification defined by this specification.
The algorithm takes the following input variables:
origin
of the signing request - in the case of a browser wallet implementation - the origin of the page which requested the signin via the provider.allowedSchemes
- a list of schemes allowed by the Wallet.defaultScheme
- a scheme to assume when none was provided. Wallet implementers in the browser SHOULD use https
.origin
being localhost.The algorithm is described as follows:
scheme
was not provided, then assign defaultScheme
as scheme
.scheme
is not contained in allowedSchemes
, then the scheme
is not expected and the Wallet MUST reject the request. Wallet implementers in the browser SHOULD limit the list of allowedSchemes
to just 'https'
unless a developer mode is activated.scheme
does not match the scheme of origin
, the Wallet SHOULD reject the request. Wallet implementers MAY show a warning instead of rejecting the request if a developer mode is activated. In that case the Wallet continues processing the request.host
part of the domain
and origin
do not match, the Wallet MUST reject the request unless the Wallet is in developer mode. In developer mode the Wallet MAY show a warning instead and continues processing the request.domain
and origin
have mismatching subdomains, the Wallet SHOULD reject the request unless the Wallet is in developer mode. In developer mode the Wallet MAY show a warning instead and continues processing the request.port
be the port component of domain
, and if no port is contained in domain
, assign port
the default port specified for the scheme
.port
is not empty, then the Wallet SHOULD show a warning if the port
does not match the port of origin
.port
is empty, then the Wallet MAY show a warning if origin
contains a specific port. (Note 'https' has a default port of 443 so this only applies if allowedSchemes
contain unusual schemes)scheme
, domain
, address
, statement
, and resources
. Other present fields MUST also be made available to the user prior to signing either by default or through an extended interface.Write a specification for how Sign-In with Ethereum should work. The specification should be simple and generally follow existing practices. Avoid feature bloat, particularly the inclusion of lesser-used projects who see getting into the specification as a means of gaining adoption. The core specification should be decentralized, open, non-proprietary, and have long-term viability. It should have no dependence on a centralized server except for the servers already being run by the application that the user is signing in to. The basic specification should include: Ethereum accounts used for authentication, ENS names for usernames (via reverse resolution), and data from the ENS name’s text records for additional profile information (e.g. avatar, social media handles, etc).
Additional functional requirements:
Why ERC-191 (Signed Data Standard) over EIP-712 (Ethereum typed structured data hashing and signing)
ERC-191 produces more human-readable messages, while EIP-712 creates signing outputs for machine consumption, with most wallets not displaying the payload to be signed in a manner friendly to humans. (1)
EIP-712 has the advantage of on-chain representation and on-chain verifiability, such as for their use in metatransactions, but this feature is not relevant for the specification's scope. (2)
The following concerns are out of scope for this version of the specification to define:
resources
field as claims or other resources.The following items are considered for future support either through an iteration of this specification or new work items using this specification as a dependency.
A reference implementation is available here.
nonce
to prevent replay attacks, which it verifies after signing. Privacy-preserving alternatives are suggested in the next section on preventing replay attacks.nonce
or requested set of resources
. When communicating to the server, the wallet SHOULD take precautions to protect user privacy by mitigating user information revealed as much as possible.address
out of many, or a preferred ENS name out of many.nonce
SHOULD be selected per session initiation with enough entropy to prevent replay attacks, a man-in-the-middle attack in which an attacker is able to capture the user's signature and resend it to establish a new session for themselves.nonce
values, such as one derived from a recent Ethereum block hash or a recent Unix timestamp.There are several cases where an implementer SHOULD check for state changes as they relate to sessions.
resources
change, the server SHOULD invalidate sessions appropriately. However, the interpretation of resources
is out of scope of this specification.Copyright and related rights waived via CC0.