Skip to content

SIWE 2.0 Release

Compare
Choose a tag to compare
@w4ll3 w4ll3 released this 12 May 00:32
· 59 commits to main since this release
eb64c77

SIWE 2.0 has been released. The interfaces have been updated to allow consistent usage across languages for SIWE message parsing, creation, and verification. Message parsing has been split into its own package, siwe-parser, allowing implementers to utilize this functionality standalone without importing larger cryptographic dependencies.

As a result, this update introduces the following breaking changes (hence the major version update) and implements stricter checks from the EIP-4361 specification:

  • validate(…) was deprecated and renamed to verify(…) with a new API. A backwards-compatible helper function exists to allow existing implementers to upgrade without concern for changed behavior, but SIWE 1.0 users are advised to review the upgrade section below.
  • ethers has been updated to a peer dependency, allowing for more efficient builds.
  • EIP-55 validation of EIP-155 is now enforced, and non-EIP-155 messages are considered as invalid.
  • The type and signature properties have been removed from SiweMessage.
  • The not-before message field is now checked during verify.
  • This update introduces more granular error types returned after verification or message parsing failures: EXPIRED_MESSAGE, INVALID_DOMAIN, DOMAIN_MISMATCH, NONCE_MISMATCH, INVALID_ADDRESS, INVALID_URI, INVALID_NONCE, NOT_YET_VALID_MESSAGE, INVALID_SIGNATURE, INVALID_TIME_FORMAT, INVALID_MESSAGE_VERSION, and UNABLE_TO_PARSE.

Upgrading from SIWE 1.x to 2.0

For most implementers, the existing code will continue to work as expected without changes, but there will be a warning message that validate() has been deprecated, and may be removed in future versions. To get rid of this warning, you can simply update instances of validate(signature) to verify({ signature: signature }).

validate (SIWE 1.x) vs verify (SIWE 2.0)

Instead of validate(...), SIWE 2.0 uses verify(params, opts). The verify function accepts the primary argument params, which satisfies the following interface:

export interface VerifyParams {
    /** Signature of the message signed by the wallet */
    signature: string;

    /** RFC 4501 dns authority that is requesting the signing. */
    domain?: string;

    /** Randomized token used to prevent replay attacks, at least 8 alphanumeric characters. */
    nonce?: string;

    /**ISO 8601 datetime string of the current time. */
    time?: string;
}

The opts argument contains the options which dictate how the verification should proceed, namely:

export interface VerifyOpts {
    /** ethers provider to be used for EIP-1271 validation */
    provider?: providers.Provider;

    /** If the library should reject promises on errors, defaults to false */
    suppressExceptions?: boolean;
}

Finally, the verify(...) function returns an object of type SiweResponse defined as:

export interface SiweResponse {
    /** Boolean representing if the message was verified with success. */
    success: boolean;

    /** If present `success` MUST be false and will provide extra information on the failure reason. */
    error?: SiweError;

    /** Original message that was verified. */
    data: SiweMessage;
}

With the suppressExceptions option above, a SiweResponse with a populated error will be resolved instead of the promise being rejected, allowing for normal control flow handling. However, by default, promises are rejected to ensure defensive programming practices.