BETTER-AUTH. UI
Plugins

Sign In With Ethereum

Add ERC-4361 wallet sign-in and connected wallet settings to your Solid/Zaidan app.

The SIWE plugin adds wallet sign-in backed by Better Auth's siwe() plugin, with optional email collection and a security settings card for connected wallets.

It contributes:

  • A "Continue with Ethereum" button on sign-in views
  • An optional email dialog when the plugin's email mode is "optional" or "required"
  • A <WalletAccounts /> security card for connecting, promoting, and removing wallets

Setup

Configure the Better Auth server

Add siwe() with a secure nonce generator and an ERC-4361 verifier, then apply the plugin schema.

src/lib/auth.ts
import { betterAuth } from "better-auth"
import { siwe } from "better-auth/plugins"
import { verifyMessage } from "viem"
import { generateSiweNonce } from "viem/siwe"

export const auth = betterAuth({
  // ...
  plugins: [
    siwe({ 
      domain: "app.example.com",
      getNonce: async () => generateSiweNonce(),
      verifyMessage: async ({ message, signature, address }) =>
        verifyMessage({
          address: address as `0x${string}`,
          message,
          signature: signature as `0x${string}`
        })
    })
  ]
})

Add the matching client plugin

src/lib/auth-client.ts
import { createAuthClient } from "better-auth/solid"
import { siweClient } from "better-auth/client/plugins"

export const authClient = createAuthClient({
  plugins: [siweClient()] 
})

Install the UI plugin

npx shadcn@latest add https://better-auth-ui.com/r/solid/siwe.json

Register the plugin

connector is yours to supply. It bridges the plugin to whichever wallet library you use, so BAUI never depends on one.

src/components/providers.tsx
import { AuthProvider } from "@/components/auth/auth-provider"
import { siwePlugin } from "@/lib/auth/siwe-plugin"
import { authClient } from "@/lib/auth-client"

export function Providers(props: { children?: JSX.Element }) {
  return (
    <AuthProvider
      authClient={authClient}
      navigate={navigate}
      plugins={[
        siwePlugin({ 
          connector,
          domain: "app.example.com",
          uri: "https://app.example.com"
        })
      ]}
    >
      {props.children}
    </AuthProvider>
  )
}

Pass walletManager as well to render the <WalletAccounts /> security card. Without it the plugin only contributes the sign-in button.

domain and uri must match what the server verifies. A mismatch makes every signature fail verification.

Runtime prerequisites

  • Server: siwe() from better-auth/plugins, with getNonce and verifyMessage.
  • Client: siweClient() from better-auth/client/plugins.
  • App: a wallet connector, and a wallet manager if you want the settings card.
  • Runtime API: SIWE query and mutation options from Solid runtime APIs.

Copied files

  • src/lib/auth/siwe-plugin.ts
  • src/components/auth/siwe/sign-in-ethereum-button.tsx
  • src/components/auth/siwe/wallet-accounts.tsx

After install these files are yours. Restyle the wallet rows, change how addresses are shortened, or swap the dialog for your wallet library's own modal.

Options

Prop

Type

Localization

Prop

Type

Last updated on

On this page