{"id":16772,"library":"better-auth-siws","title":"Better Auth Sign-In With Solana (SIWS) Plugin","description":"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.","status":"active","version":"0.1.3","language":"javascript","source_language":"en","source_url":null,"tags":["javascript","better-auth","solana","auth","plugin","siws","typescript"],"install":[{"cmd":"npm install better-auth-siws","lang":"bash","label":"npm"},{"cmd":"yarn add better-auth-siws","lang":"bash","label":"yarn"},{"cmd":"pnpm add better-auth-siws","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"This package is a plugin for Better Auth and requires it as a peer dependency.","package":"better-auth","optional":false},{"reason":"Used for base58 encoding of Solana signatures during the SIWS verification process.","package":"bs58","optional":false}],"imports":[{"note":"Used for configuring the SIWS server plugin within your Better Auth instance. This package is ESM-first.","wrong":"const siwsPlugin = require('better-auth-siws').siwsPlugin;","symbol":"siwsPlugin","correct":"import { siwsPlugin } from 'better-auth-siws';"},{"note":"Used for configuring the SIWS client plugin within your Better Auth client instance. Note the explicit '/client' subpath.","wrong":"import { siwsClientPlugin } from 'better-auth-siws';","symbol":"siwsClientPlugin","correct":"import { siwsClientPlugin } from 'better-auth-siws/client';"},{"note":"A utility function to programmatically construct the canonical Sign-In With Solana message string.","wrong":"const buildSiwsMessage = require('better-auth-siws').buildSiwsMessage;","symbol":"buildSiwsMessage","correct":"import { buildSiwsMessage } from 'better-auth-siws';"}],"quickstart":{"code":"import bs58 from \"bs58\";\nimport { buildSiwsMessage } from \"better-auth-siws\";\nimport { createAuthClient } from \"better-auth/client\";\nimport { siwsClientPlugin } from \"better-auth-siws/client\";\n\n// 1. Initialize Better Auth client with SIWS plugin\nexport const clientAuth = createAuthClient({\n  baseURL: \"https://app.example.com/api/auth\", // Ensure this matches your server's baseURL\n  plugins: [siwsClientPlugin()],\n});\n\n/**\n * Simulates a Solana wallet with publicKey and signMessage capabilities.\n * In a real app, this would come from a wallet adapter (e.g., @solana/wallet-adapter).\n */\nconst mockWallet = {\n  publicKey: { toBase58: () => 'HbC8N9p6jR8g7A6y5X4Z3W2V1U0T9S8Q' },\n  signMessage: async (data: Uint8Array) => {\n    // In a real app, this would prompt the user to sign\n    // For this example, returning a dummy signature\n    console.log(\"Wallet signing message:\", new TextDecoder().decode(data));\n    return new Uint8Array(Array(64).fill(0)); // Dummy 64-byte signature\n  }\n};\n\nasync function signInWithSolana(wallet: typeof mockWallet) {\n  // 2. Request a nonce from the server\n  const address = wallet.publicKey.toBase58();\n  const { nonce, domain, uri } = await clientAuth.api.start({\n    body: { address },\n  });\n\n  // 3. Build the canonical SIWS message for signing\n  const message = buildSiwsMessage({\n    domain,\n    address,\n    uri,\n    nonce,\n    issuedAt: new Date().toISOString(),\n  });\n\n  // 4. Have the user's wallet sign the message\n  const signatureBytes = await wallet.signMessage(new TextEncoder().encode(message));\n  const signature = bs58.encode(signatureBytes);\n\n  // 5. Send signed message and signature to the server for verification\n  const result = await clientAuth.api.verify({\n    body: { address, message, signature },\n  });\n\n  console.log(\"Sign-In successful!\");\n  console.log(\"User session:\", result);\n  return result;\n}\n\n// Example usage:\nsignInWithSolana(mockWallet).catch(console.error);\n","lang":"typescript","description":"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."},"warnings":[{"fix":"Ensure `siwsPlugin({ domain: 'app.example.com' })` on the server exactly matches your application's domain. Also, `betterAuth({ security: { trustedOrigins: [...] } })` should include the exact client origin.","message":"The 'domain' configured in the `siwsPlugin` on your server MUST precisely match the domain your application is hosted on (without protocol) and align with the 'domain' returned by the `/siws/start` endpoint. A mismatch will cause signature verification to fail due to the SIWS specification.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Inform users about the time limit or consider increasing `nonceTtlSeconds` on the server if longer delays are expected. For example: `siwsPlugin({ nonceTtlSeconds: 600 })`.","message":"The `nonceTtlSeconds` configured on the server-side `siwsPlugin` (default: 300 seconds) defines how long a generated nonce remains valid. If the user takes too long to sign the message and send it for verification, the nonce may expire, leading to verification failure.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Ensure you are using a compatible Solana wallet adapter (e.g., `@solana/wallet-adapter`) and that the wallet is connected and exposes the `signMessage` function as expected.","message":"The client-side SIWS flow requires a connected Solana wallet that implements a `signMessage` method which accepts a `Uint8Array` message and returns a `Promise<Uint8Array>` signature. Wallets or adapter libraries that provide different APIs for message signing will not work directly.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Verify your `better-auth` server configuration, ensuring `baseURL` is correct and all client origins are listed in `security.trustedOrigins`.","message":"This package is a plugin for `better-auth`. Proper functioning relies on `better-auth` itself being correctly configured, especially its `baseURL` and `security.trustedOrigins`. Requests from unlisted origins will be rejected by Better Auth's security middleware, preventing SIWS flow completion.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Check the `domain` option passed to `siwsPlugin({ domain: '...' })` on your server to ensure it precisely matches the `domain` of your application where the SIWS flow is initiated.","cause":"The 'domain' in the signed SIWS message does not match the 'domain' configured in the server's `siwsPlugin` instance.","error":"Error: SIWS verification failed: Domain mismatch."},{"fix":"Expedite the client-side signing process, or increase the `nonceTtlSeconds` option in your server's `siwsPlugin` configuration (e.g., `siwsPlugin({ nonceTtlSeconds: 600 })`).","cause":"The time elapsed between the server issuing a nonce and the client submitting the signed message for verification exceeded the configured `nonceTtlSeconds`.","error":"Error: SIWS verification failed: Nonce expired."},{"fix":"Ensure a compatible Solana wallet (e.g., via `@solana/wallet-adapter`) is connected and the wallet instance provides the `signMessage` function with the expected signature (`(data: Uint8Array) => Promise<Uint8Array>`).","cause":"The connected Solana wallet object does not expose a `signMessage` method, or it's not available when the SIWS signing attempt is made.","error":"TypeError: wallet.signMessage is not a function"},{"fix":"Add the full origin URL of your frontend application (e.g., `https://app.example.com`) to the `trustedOrigins` array in your `betterAuth({ security: { trustedOrigins: [...] } })` server configuration.","cause":"The `Origin` header of the client request is not included in the `trustedOrigins` array configured in your `better-auth` server instance.","error":"Error: Unauthorized origin for SIWS start/verify endpoint."}],"ecosystem":"npm","meta_description":null}