Skip to main content
Skill — Copyable reference implementation. Use as-is or customize. See Skills Philosophy.
Sign-In with Ethereum (SIWE) enables passwordless authentication using Ethereum accounts. Users prove ownership of their address by signing a structured message (EIP-4361).

Overview

SIWE authentication flow:
  1. Server generates a unique nonce
  2. Client creates a SIWE message with the nonce
  3. User signs the message with their wallet
  4. Server verifies the signature matches the address in the message
  5. Server creates a session for the authenticated user

Creating SIWE Messages

Use Siwe.create() to construct a message with required fields:

Adding Optional Fields

Include statement, expiration, and resources for enhanced messages:

Custom Nonce

For server-generated nonces, pass your own value:

Formatting Messages for Signing

Convert the message object to the EIP-4361 text format for wallet signing:
Output:

Signing SIWE Messages

The message hash uses EIP-191 personal sign format. Sign with any Ethereum wallet:

Using PrivateKeySigner (Server-side or Testing)

Using Browser Wallet (Client-side)

Verifying SIWE Signatures

Basic Verification

Siwe.verify() checks that the signature was created by the address in the message:

Full Message Verification

Siwe.verifyMessage() validates both the signature and message constraints (expiration, notBefore):

Validation Without Signature

Validate message structure and timestamps before signature verification:

Testing with Custom Time

For testing expiration logic:

Session Management Patterns

Server-Side Session Flow

Parsing Messages

Parse a formatted message string back to an object:

Domain Binding Security

Always verify the domain matches your application to prevent phishing:

Complete Example

Full client-server authentication flow:

Error Handling

Handle all validation error types:

API Reference

FunctionDescription
Siwe.create(params)Create a new SIWE message
Siwe.format(message)Convert message to EIP-4361 text
Siwe.parse(text)Parse EIP-4361 text to message object
Siwe.validate(message, options?)Validate message structure and timestamps
Siwe.verify(message, signature)Verify signature matches address
Siwe.verifyMessage(message, signature, options?)Full validation + signature verification
Siwe.generateNonce(length?)Generate random alphanumeric nonce
Siwe.getMessageHash(message)Get EIP-191 hash for signing