Better Auth Sign-In With Solana (SIWS) Plugin

0.1.3 · active · verified Wed Apr 22

better-auth-siws is a specialized plugin designed to integrate Sign-In With Solana (SIWS) functionality into applications utilizing the Better Auth framework. Currently at version 0.1.3, this package provides both server-side and client-side plugins (`siwsPlugin` and `siwsClientPlugin` respectively) along with a utility (`buildSiwsMessage`) to construct the canonical SIWS message. It streamlines the implementation of SIWS by offering `start` and `verify` endpoints, abstracting away much of the cryptographic and session management complexity when paired with Better Auth. The package is actively maintained and extends Better Auth's capabilities to support Solana-based authentication flows, differentiating itself by providing a tightly integrated solution specifically for the Better Auth ecosystem.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates a complete client-side Sign-In With Solana (SIWS) flow using `better-auth-siws`. It covers initializing the Better Auth client, requesting a nonce from the server, building the canonical SIWS message, having a mock Solana wallet sign the message, and finally verifying the signature with the server to establish a user session. This illustrates the typical steps a user would take in a web application.

import bs58 from "bs58";
import { buildSiwsMessage } from "better-auth-siws";
import { createAuthClient } from "better-auth/client";
import { siwsClientPlugin } from "better-auth-siws/client";

// 1. Initialize Better Auth client with SIWS plugin
export const clientAuth = createAuthClient({
  baseURL: "https://app.example.com/api/auth", // Ensure this matches your server's baseURL
  plugins: [siwsClientPlugin()],
});

/**
 * Simulates a Solana wallet with publicKey and signMessage capabilities.
 * In a real app, this would come from a wallet adapter (e.g., @solana/wallet-adapter).
 */
const mockWallet = {
  publicKey: { toBase58: () => 'HbC8N9p6jR8g7A6y5X4Z3W2V1U0T9S8Q' },
  signMessage: async (data: Uint8Array) => {
    // In a real app, this would prompt the user to sign
    // For this example, returning a dummy signature
    console.log("Wallet signing message:", new TextDecoder().decode(data));
    return new Uint8Array(Array(64).fill(0)); // Dummy 64-byte signature
  }
};

async function signInWithSolana(wallet: typeof mockWallet) {
  // 2. Request a nonce from the server
  const address = wallet.publicKey.toBase58();
  const { nonce, domain, uri } = await clientAuth.api.start({
    body: { address },
  });

  // 3. Build the canonical SIWS message for signing
  const message = buildSiwsMessage({
    domain,
    address,
    uri,
    nonce,
    issuedAt: new Date().toISOString(),
  });

  // 4. Have the user's wallet sign the message
  const signatureBytes = await wallet.signMessage(new TextEncoder().encode(message));
  const signature = bs58.encode(signatureBytes);

  // 5. Send signed message and signature to the server for verification
  const result = await clientAuth.api.verify({
    body: { address, message, signature },
  });

  console.log("Sign-In successful!");
  console.log("User session:", result);
  return result;
}

// Example usage:
signInWithSolana(mockWallet).catch(console.error);

view raw JSON →