Documentation Index Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
Use this file to discover all available pages before exploring further.
Try it Live Run SIWE examples in the interactive playground
New to SIWE? Start with Fundamentals for guided examples and authentication concepts.
Type Definition
Sign-In with Ethereum (EIP-4361) implementation for decentralized authentication. Creates structured messages users sign with private keys, proving address ownership without key exposure.
Authentication Flow
┌──────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Frontend │ │ Wallet │ │ Backend │ │ Database │
└──────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│ │ │ │
│ 1. Request Nonce │ │ │
├────────────────────────────────────────> │ │
│ │ │ │
│ │ Generate nonce │ │
│ │ Store for 5min │──────────> │
│ 2. Get nonce │ │ │
│ <────────────────────────────────────────┤ │
│ │ │ │
│ 3. Create message │ │ │
│ with nonce │ │ │
├────────────────────>│ │ │
│ │ │ │
│ 4. Sign message │ │ │
│ <────────────────┤ │ │ │
│ │ signature │ │
│ 5. Verify message │ │ │
├────────────────────────────────────────> │ │
│ │ │ │
│ │ Check nonce │ │
│ │ Verify sig │──────────> │
│ │ Check valid │ <──────────┤
│ │ Create token │ │
│ 6. Session token │ │ │
│ <────────────────────────────────────────┤ │
│ │ │ │
└──────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
Message Structure
A SIWE message is a human-readable text format combining user intent with cryptographic proof:
example.com wants you to sign in with your Ethereum account:
0x742d35Cc6634C0532925a3b844Bc9e7595f51e3e
Sign in to Example App
URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: testnonce123
Issued At: 2024-11-06T12:00:00.000Z
Expiration Time: 2024-11-06T13:00:00.000Z
Not Before: 2024-11-06T11:00:00.000Z
Resources:
- https://example.com/api/user
- https://example.com/api/profile
Key components:
Domain (RFC 4501): Where the message is being signed for
Address : Which account is signing
URI : What resource is being accessed
Statement : Human-readable context
Chain ID : Which blockchain
Nonce : One-time value, prevents replay attacks
Timestamps : Validity window
Resources : Optional list of what’s being granted access to
Factory
Siwe ( params : MessageParams ): Siwe
Creates Siwe message instance from parameters.
Parameters:
params.domain: RFC 4501 dns authority
params.address: AddressType performing signing
params.uri: RFC 3986 URI
params.chainId: EIP-155 Chain ID
params.statement?: Human-readable assertion (optional)
params.expirationTime?: ISO 8601 expiration (optional)
params.notBefore?: ISO 8601 valid-from time (optional)
params.requestId?: System identifier (optional)
params.resources?: Resource URIs (optional)
params.nonce?: Custom nonce (auto-generated if omitted)
params.issuedAt?: Custom timestamp (current time if omitted)
Returns: Siwe message instance
Static Constructors
Siwe.create(params)
create ( params : MessageParams ): BrandedMessage
Create message with defaults. Same as factory.
Siwe.parse(text)
parse ( text : string ): BrandedMessage
Parse EIP-4361 formatted string to message.
Throws: Error if format invalid
Static Utilities
format ( message : BrandedMessage ): string
Format message to EIP-4361 string for signing.
Validation
Siwe.validate(message, options?)
validate ( message : BrandedMessage , options ?: { now? : Date }): ValidationResult
Validate message structure and timestamps.
Returns: { valid: true } or { valid: false, error: ValidationError }
Signing & Verification
Siwe.getMessageHash(message)
getMessageHash ( message : BrandedMessage ): Uint8Array
Get EIP-191 personal sign message hash (32 bytes).
Siwe.verify(message, signature)
verify ( message : BrandedMessage , signature : Signature ): boolean
Verify signature matches message address.
Parameters:
signature: 65-byte signature (r + s + v)
Returns: true if valid
Siwe.verifyMessage(message, signature, options?)
verifyMessage ( message : BrandedMessage , signature : Signature , options ?: { now? : Date }): ValidationResult
Combined validation and verification.
Nonce Generation
Siwe.generateNonce(length?)
generateNonce ( length ?: number ): string
Generate cryptographically secure random nonce.
Parameters:
length: Nonce length (default 11, min 8)
Returns: Base62 alphanumeric string
Instance Methods
All static utilities available as instance methods:
const message = Siwe . create ({
domain: "example.com" ,
address: userAddress ,
uri: "https://example.com" ,
chainId: 1 ,
});
message . format () // string
message . validate () // ValidationResult
message . getMessageHash () // Uint8Array
message . verify ( signature ) // boolean
Instance methods delegate to BrandedSiwe namespace functions.
Types
type BrandedMessage = {
domain : string ;
address : AddressType ;
uri : string ;
version : string ;
chainId : number ;
nonce : string ;
issuedAt : string ;
statement ?: string ;
expirationTime ?: string ;
notBefore ?: string ;
requestId ?: string ;
resources ?: string [];
}
type Signature = Uint8Array ; // 65 bytes: r (32) + s (32) + v (1)
type ValidationResult =
| { valid : true }
| { valid : false ; error : ValidationError };
type ValidationError =
| { type : "invalid_domain" ; message : string }
| { type : "invalid_address" ; message : string }
| { type : "invalid_uri" ; message : string }
| { type : "invalid_version" ; message : string }
| { type : "invalid_chain_id" ; message : string }
| { type : "invalid_nonce" ; message : string }
| { type : "invalid_timestamp" ; message : string }
| { type : "expired" ; message : string }
| { type : "not_yet_valid" ; message : string }
| { type : "signature_mismatch" ; message : string };
See BrandedSiwe for branded type details.
Implementation
Delegates to BrandedSiwe namespace
Extends Object.prototype
Structured message format per EIP-4361
Supports optional fields via conditional spreading
Quick Start
import { Siwe , Address } from 'tevm' ;
// Create message
const message = Siwe . create ({
domain: "example.com" ,
address: Address ( "0x..." ),
uri: "https://example.com/login" ,
chainId: 1 ,
statement: "Sign in to Example App" ,
});
// Format for wallet signing
const text = message . format ();
// User signs with wallet
const signature = await wallet . signMessage ( text );
// Validate and verify
const result = Siwe . verifyMessage ( message , signature );
if ( result . valid ) {
// Authenticated
}
Common Patterns
Authentication Flow
// Backend: Generate nonce
const nonce = Siwe . generateNonce ();
storeNonce ( userId , nonce );
// Frontend: Create and sign message
const message = Siwe . create ({
domain: window . location . host ,
address: userAddress ,
uri: window . location . origin ,
chainId: await provider . getChainId (),
nonce ,
});
const signature = await wallet . signMessage ( message . format ());
// Backend: Verify
const parsed = Siwe . parse ( messageText );
const result = Siwe . verifyMessage ( parsed , signature );
if ( result . valid && verifyNonce ( parsed . nonce )) {
createSession ( parsed . address );
}
Session Management
const message = Siwe . create ({
domain: "example.com" ,
address: userAddress ,
uri: "https://example.com" ,
chainId: 1 ,
expirationTime: new Date ( Date . now () + 3600000 ). toISOString (),
});
// Validate at session use
const result = message . validate ({ now: new Date () });
if ( ! result . valid ) {
requestReauth ();
}
API Documentation
Constructors
Creating SIWE messages from parameters or text.
View constructors →
Parsing
Parse EIP-4361 formatted strings to message objects.
View parsing →
Validation
Validate message structure and timestamps.
View validation →
Signing & Verification
Create hashes and verify signatures with addresses.
View signing →
Utilities
Nonce generation and helper functions.
View utilities →
Usage Patterns
Real-world authentication and session patterns.
View patterns →
Quick Reference: Security Checklist
Always Verify:
Domain matches request origin
Nonce is fresh and single-use
Signature is valid
Message not expired
Address matches session
HTTPS in production
Siwe (Effect) - Effect.ts integration with Schema validation
Address - 20-byte Ethereum addresses used in messages
Signature - 65-byte signatures (r + s + v) for verification
Keccak256 - 32-byte hashes from message signing
References