/simple-siwe

Simple implementation Sign-In with Ethereum (SIWE) library with Viem v2

Primary LanguageTypeScriptMIT LicenseMIT

Archived because wevm/viem#2280

simple-siwe

Version Downloads install size npm bundle size

publint | arethetypeswrong

Simple implementation Sign-In with Ethereum (SIWE) eip-4361 library with Viem v2

  • 🌱 Lightweight, minified ~1kb
  • 🚫 No Dependency (only viem as peer)
  • 🌳 Tree-shakable
  • ✍️ TypeScript/Esm
  • ✅ 100% test coverage

Comparison

Package Size ▼ Engine Verify Parser Downloads
simple-siwe install size Viem 2 average own (beta) Download month
eip-login install size Viem 2 low - Download month
siwviem install size Viem 1 high siwe-parser Download month
siwe install size ethers high siwe-parser Download month
siwe-viem install size Viem 2 high siwe-parser Download month

Installation and Usage

You can install simple-siwe and viem using npm, yarn, or pnpm. Here's how you can install it using pnpm:

pnpm add simple-siwe viem

After importing simple-siwe, you can use its functions in your TypeScript code. Here's a basic example of how you can use the functions:

import {
  parseMessage,
  generateNonce,
  verify,
  prepareMessage,
} from 'simple-siwe'

// Generate a nonce
const nonce = generateNonce()

// Prepare a message for signing
const message = prepareMessage({
  domain: 'example.com', // RFC 4501 dns authority that is requesting the signing
  address: '0x1234567890123456789012345678901234567890', // Ethereum address performing the signing
  statement: 'This is a sample statement for signing.', // Human-readable ASCII assertion
  uri: 'https://example.com/resource', // RFC 3986 URI referring to the resource
  version: '1.0', // Current version of the message
  chainId: 1, // EIP-155 Chain ID
  nonce, // Randomized token used to prevent replay attacks
  issuedAt: new Date().toISOString(), // ISO 8601 datetime string of the current time
})

// Verify a message with a signature
const isVerified = await verify({ message, signature: '0x...' })

Backend & Frontend Implementation

Express.js example with a simple frontend implementation.

Backend side with

import express from 'express'
import { generateNonce, prepareMessage, verify } from 'simple-siwe'

const app = express()

app.get('/nonce', (req, res) => {
  const nonce = generateNonce()
  res.json({ nonce })
})

app.post('/verify', async (req, res) => {
  const { message, signature } = req.body

  try {
    const isValid = await verify({ message, signature })

    // save session logic here
    res.send({ isValid })
  } catch (error) {
    res.status(400).send({ isValid: false, error: error.message })
  }
})

app.listen(3000)

Frontend side:

import { generateNonce, prepareMessage, verify } from 'simple-siwe'
import type { SiweMessage } from 'simple-siwe'

// 1. Fetch nonce from the backend and prepare a message
const { nonce } = await fetch('http://localhost:3000/nonce').then((res) =>
  res.json()
)

// 2. Prepare a message with the nonce
const message: SiweMessage = {
  // ... message properties
  nonce,
}

const preparedMessage = prepareMessage(message)

// 3. Sign the message using wagmi or other signing methods
const signature = await signMessage({ message: preparedMessage })

// 4. Verify the signature on the backend
try {
  const { isValid } = await fetch('http://localhost:3000/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ message, signature }),
  }).then((res) => res.json())

  // 5. Done. Use the isValid boolean to determine if the signature is valid

  if (isValid) {
    // redirect to the dashboard
  } else {
    // show an error message
  }
} catch (error) {
  console.error(error)
}

Troubleshooting

TypeError: Crypto.randomUUID is not a function

The nonce is generated using the Crypto: randomUUID() method, which may not be supported in all browsers or Node.js versions. Consider using polyfills to ensure compatibility.

Related

License

This project is licensed under the terms of the MIT license.