A lightweight TypeScript implementation of Sign-In with Ethereum (EIP-4361).
Most SIWE implementations depend on heavy Ethereum libraries like ethers.js or viem. This library uses only @noble/secp256k1 and @noble/hashes for cryptographic operations, resulting in a much smaller bundle size for applications that don't need a full Ethereum library.
npm install @anders94/siweimport { SiweMessage } from '@anders94/siwe';
const message = new SiweMessage({
domain: 'myapp.com',
address: '0x1234567890123456789012345678901234567890',
statement: 'Sign in to My App',
uri: 'https://myapp.com',
version: '1',
chainId: 1,
nonce: 'randomNonce123',
issuedAt: new Date().toISOString(),
expirationTime: new Date(Date.now() + 3600000).toISOString(), // optional
notBefore: new Date().toISOString(), // optional
requestId: 'request-123', // optional
resources: ['https://myapp.com/api'] // optional
});
// Get the message string to be signed
const messageString = message.prepareMessage();import { SiweMessage } from '@anders94/siwe';
const messageString = `myapp.com wants you to sign in with your Ethereum account:
0x1234567890123456789012345678901234567890
Sign in to My App
URI: https://myapp.com
Version: 1
Chain ID: 1
Nonce: randomNonce123
Issued At: 2024-01-01T00:00:00.000Z`;
const message = SiweMessage.fromString(messageString);import { SiweMessage } from '@anders94/siwe';
const message = new SiweMessage({
domain: 'myapp.com',
address: userAddress,
uri: 'https://myapp.com',
version: '1',
chainId: 1,
nonce: 'randomNonce123',
issuedAt: new Date().toISOString()
});
try {
// Validates signature and checks expiration/notBefore times
await message.validate(signature);
console.log('Signature valid!');
} catch (error) {
console.error('Validation failed:', error.message);
}import { checkSignature } from '@anders94/siwe';
const isValid = await checkSignature(message, signature, expectedAddress);| Property | Type | Required | Description |
|---|---|---|---|
domain |
string |
Yes | The domain requesting the sign-in |
address |
string |
Yes | Ethereum address (0x-prefixed) |
uri |
string |
Yes | URI of the resource |
version |
string |
Yes | SIWE version (typically "1") |
chainId |
number |
Yes | EIP-155 chain ID |
nonce |
string |
Yes | Randomized token for replay protection |
issuedAt |
string |
Yes | ISO 8601 timestamp |
statement |
string |
No | Human-readable message |
expirationTime |
string |
No | ISO 8601 expiration time |
notBefore |
string |
No | ISO 8601 time before which message is invalid |
requestId |
string |
No | Request identifier |
resources |
string[] |
No | List of resource URIs |
prepareMessage(): string- Returns the EIP-4361 formatted message stringtoMessage(): string- Alias forprepareMessage()validate(signature: string): Promise<SiweMessage>- Validates signature and time constraintsstatic fromString(str: string): SiweMessage- Parses an EIP-4361 message string
function checkSignature(
message: string,
signature: string,
expectedAddress: string
): Promise<boolean>Low-level function to verify an Ethereum signature matches an expected address.
MIT