npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pinklemon8/better-auth-siws

v0.1.4

Published

Sign In With Solana (SIWS) plugin for Better Auth — wallet authentication, linking, and ready-made React components

Readme

better-auth-siws

Sign In With Solana (SIWS) plugin for Better Auth — wallet authentication, linking, and ready-made React components.

Features

  • Server plugin — SIWS nonce generation + signature verification, session creation
  • Client pluginsignIn.solana(), wallet management methods
  • Wallet linking — Link/unlink Solana wallets to existing accounts
  • React components — Drop-in <SolanaSignInButton> and <SolanaLinkWallet>
  • Anonymous mode — Optionally allow sign-up with wallet only (no email required)
  • Uses @solana/wallet-standard-util for cryptographic verification

Installation

npm install @pinklemon8/better-auth-siws @solana/wallet-adapter-react @solana/wallet-adapter-react-ui @solana/wallet-standard-features @solana/wallet-standard-util @solana/web3.js

Quick Start

1. Server Setup

// auth.ts
import { betterAuth } from "better-auth";
import { siws } from "@pinklemon8/better-auth-siws";
import { siwsLink } from "@pinklemon8/better-auth-siws/link";

export const auth = betterAuth({
  // ...your config
  plugins: [
    siws({
      // All options are optional
      statement: "Sign in to MyApp with your Solana wallet",
      chainId: "mainnet",
      nonceExpiryMs: 5 * 60 * 1000, // 5 minutes (default)
      anonymous: false, // true = allow sign-up with wallet only
    }),
    siwsLink(), // adds /siws/link, /siws/unlink, /siws/wallets endpoints
  ],
});

2. Client Setup

// auth-client.ts
import { createAuthClient } from "better-auth/react";
import { siwsClient } from "@pinklemon8/better-auth-siws/client";

export const authClient = createAuthClient({
  plugins: [siwsClient()],
});

3. React Components (Optional)

Drop-in sign-in button:

import { SolanaSignInButton } from "@pinklemon8/better-auth-siws/react";

function LoginPage() {
  return (
    <SolanaSignInButton
      onSuccess={(user) => {
        console.log("Signed in:", user);
        window.location.href = "/dashboard";
      }}
      onError={(err) => console.error(err)}
      className="btn btn-primary"
    />
  );
}

Wallet linking for settings pages:

import { SolanaLinkWallet } from "@pinklemon8/better-auth-siws/react";

function WalletSettings() {
  return (
    <SolanaLinkWallet
      onLink={(addr) => console.log("Linked:", addr)}
      onUnlink={() => console.log("Unlinked")}
      onError={(err) => console.error(err)}
      className="btn"
      unlinkClassName="btn btn-danger"
    />
  );
}

Custom rendering for linked state:

<SolanaLinkWallet
  renderLinked={({ address, onUnlink }) => (
    <div>
      <code>{address}</code>
      <button onClick={onUnlink}>Remove</button>
    </div>
  )}
/>

API Reference

Server Plugin: siws(options?)

Registers these Better Auth endpoints:

| Endpoint | Method | Description | |---|---|---| | /siws/nonce | POST | Generate a nonce for SIWS. Body: { walletAddress } | | /siws/verify | POST | Verify signature and create session. Body: { input, output } |

Options:

| Option | Type | Default | Description | |---|---|---|---| | statement | string | Generic statement | Message shown in wallet | | chainId | string | "mainnet" | Solana chain ID | | nonceExpiryMs | number | 300000 (5 min) | Nonce TTL | | anonymous | boolean | false | Allow sign-up without pre-existing account |

Server Plugin: siwsLink(options?)

Registers wallet linking endpoints:

| Endpoint | Method | Description | |---|---|---| | /siws/link | POST | Link wallet to authenticated user | | /siws/unlink | POST | Unlink wallet. Body: { walletAddress } | | /siws/wallets | GET | List linked wallets for current user |

Client Plugin: siwsClient()

Adds these methods to your auth client:

// Sign in with Solana
authClient.signIn.solana({ input, output });

// Get nonce
authClient.solana.getNonce({ walletAddress });

// Link/unlink/list wallets
authClient.solana.linkWallet({ input, output });
authClient.solana.unlinkWallet({ walletAddress });
authClient.solana.getLinkedWallets();

React Components

| Component | Props | Description | |---|---|---| | SolanaProvider | cluster, endpoint, autoConnect | Wraps Solana wallet adapter providers | | SolanaSignInButton | baseURL, basePath, onSuccess, onError, className, disabled, cluster, endpoint | Complete sign-in button | | SolanaLinkWallet | baseURL, basePath, onLink, onUnlink, onError, className, disabled, cluster, endpoint, renderLinked | Wallet link/unlink component |

How It Works

  1. User clicks sign-in button, wallet modal opens (Phantom, Solflare, etc.)
  2. Plugin generates a nonce stored in Better Auth's verification table
  3. Wallet signs the SIWS message using adapter.signIn(input) (Wallet Standard)
  4. Plugin verifies the signature using @solana/wallet-standard-util
  5. Looks up the wallet address in the account table (providerId: "solana")
  6. Creates a session and sets the cookie

Wallet linking uses the same SIWS verification but associates the wallet with the currently authenticated user instead of creating a new session.

Requirements

  • Better Auth >= 1.2.0
  • A Solana wallet that supports SIWS (e.g., Phantom v23.11.0+, Solflare)
  • Node.js 18+ (uses crypto.getRandomValues)

License

MIT