{"id":16771,"library":"better-auth-minikit","title":"Better Auth Worldcoin Minikit Plugin","description":"The `better-auth-minikit` package provides a plugin for the `better-auth` authentication library, enabling seamless integration with Worldcoin Minikit for Sign-In With Ethereum (SIWE) based authentication flows. It is currently at version 1.0.10, indicating a stable release within its first major iteration. While a specific release cadence isn't stated, the `better-auth` ecosystem generally follows a responsive approach to updates. Key differentiators include its full SIWE implementation adapted for Minikit, robust multi-chain support for associating wallet addresses with specific chain IDs, automatic account linking for verified multiple wallet addresses, and compatibility with MiniApps via secure, partitioned session cookies (SameSite: \"none\"). It abstracts much of the SIWE complexity for `better-auth` users, focusing on secure server-side nonce generation and message verification, along with a client-side API for initiating the flow.","status":"active","version":"1.0.10","language":"javascript","source_language":"en","source_url":"https://github.com/builders-garden/better-auth-minikit","tags":["javascript","better-auth","worldcoin","minikit","plugin","typescript"],"install":[{"cmd":"npm install better-auth-minikit","lang":"bash","label":"npm"},{"cmd":"yarn add better-auth-minikit","lang":"bash","label":"yarn"},{"cmd":"pnpm add better-auth-minikit","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency, this package is a plugin for better-auth.","package":"better-auth","optional":false},{"reason":"Recommended for SIWE message parsing and validation in the server-side setup.","package":"viem","optional":true},{"reason":"Required on the client-side for signing SIWE messages with Worldcoin Minikit.","package":"@worldcoin/minikit-js","optional":true}],"imports":[{"note":"This is the server-side plugin for `better-auth` and should be imported using ESM syntax.","wrong":"const { minikit } = require('better-auth-minikit')","symbol":"minikit","correct":"import { minikit } from 'better-auth-minikit'"},{"note":"The client-side plugin has a distinct entry point at `better-auth-minikit/client`.","wrong":"import { minikitClient } from 'better-auth-minikit'","symbol":"minikitClient","correct":"import { minikitClient } from 'better-auth-minikit/client'"},{"note":"This is a TypeScript type for the client-side plugin's methods, useful for type inference and explicit typing, though often inferred by `createAuthClient`.","symbol":"AuthClientMinikit","correct":"type AuthClientMinikit = ClientPlugin<typeof minikitClient>"}],"quickstart":{"code":"import { betterAuth } from \"better-auth\";\nimport { minikit } from \"better-auth-minikit\";\nimport { generateRandomString } from \"better-auth/crypto\";\nimport { parseSiweMessage, validateSiweMessage } from \"viem/siwe\";\nimport { createAuthClient } from \"better-auth/react\";\nimport { minikitClient } from \"better-auth-minikit/client\";\nimport { MiniKit } from '@worldcoin/minikit-js';\nimport { createSiweMessage } from 'viem/siwe'; // Helper to create SIWE messages\n\n// --- Server Setup (Node.js/Edge Function) ---\nexport const auth = betterAuth({\n  plugins: [\n    minikit({\n      domain: \"app.example.com\", // Replace with your actual domain\n      getNonce: async () => {\n        return generateRandomString(32);\n      },\n      verifyMessage: async ({ message, signature, address, chainId }) => {\n        try {\n            const parsedMessage = await parseSiweMessage(message);\n            const valid = await validateSiweMessage({\n                message,\n                signature,\n                domain: \"app.example.com\",\n                nonce: parsedMessage.nonce,\n                address: address, // Ensure address is passed for robust validation\n                chainId: chainId // Ensure chainId is passed for robust validation\n            });\n            return valid;\n        } catch (e) {\n            console.error(\"SIWE message verification failed:\", e);\n            return false;\n        }\n      }\n    })\n  ]\n});\n\n// --- Client Setup (React Component or similar) ---\nconst client = createAuthClient({\n  plugins: [minikitClient()],\n  fetchOptions: {\n    credentials: \"include\", // Essential for session cookies in MiniApps\n  },\n});\n\nexport const authClient = client;\n\n// --- Client-side Usage Example (within an async function) ---\nasync function authenticateWithWorldcoin() {\n  const walletAddress = \"0x...\"; // User's actual wallet address from Minikit\n  const chainId = 1; // Example: Ethereum Mainnet\n\n  // 1. Get Nonce\n  const { data: nonceData, error: nonceError } = await authClient.minikit.getNonce({\n    walletAddress,\n    chainId\n  });\n  if (nonceError || !nonceData?.nonce) {\n    console.error(\"Failed to get nonce:\", nonceError);\n    return;\n  }\n  const nonce = nonceData.nonce;\n\n  // 2. Sign Message (using Worldcoin Minikit SDK)\n  const message = createSiweMessage({\n      domain: window.location.host,\n      address: walletAddress,\n      statement: \"Sign in to My App\",\n      uri: window.location.origin,\n      version: \"1\",\n      chainId: chainId,\n      nonce: nonce,\n  });\n\n  let signature;\n  try {\n    // This part requires Worldcoin Minikit to be initialized and available\n    const { commandPayload } = await MiniKit.commands.signMessage({\n        message: message\n    });\n    signature = commandPayload;\n  } catch (signError) {\n    console.error(\"Failed to sign message with Minikit:\", signError);\n    return;\n  }\n\n  // 3. Verify and Sign In\n  const { data: signInData, error: signInError } = await authClient.minikit.signInWithMinikit({\n    message,\n    signature,\n    walletAddress,\n    chainId,\n    user: {\n        username: \"worldcoin-user\",\n        profilePictureUrl: \"https://example.com/default.png\"\n    }\n  });\n\n  if (signInData?.success) {\n    console.log(\"Successfully signed in user:\", signInData.user);\n  } else {\n    console.error(\"Sign-in failed:\", signInError);\n  }\n}\n\n// Call the function to initiate authentication (example)\n// authenticateWithWorldcoin();","lang":"typescript","description":"This quickstart demonstrates both the server-side configuration of the `minikit` plugin for `better-auth` and the client-side setup and usage with `minikitClient`, covering nonce retrieval, SIWE message signing with Worldcoin Minikit, and final sign-in verification."},"warnings":[{"fix":"Always include `fetchOptions: { credentials: \"include\" }` in your `createAuthClient` configuration when using `better-auth-minikit`.","message":"When setting up the client, ensure `fetchOptions: { credentials: \"include\" }` is explicitly provided. This is crucial for correctly handling session cookies, especially in cross-origin or MiniApp environments where `SameSite: \"none\"` cookies are used.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Verify that `minikit({ domain: \"your-app.com\" })` on the server matches `createSiweMessage({ domain: \"your-app.com\", ... })` on the client.","message":"The `domain` parameter in the `minikit` server plugin must exactly match the `domain` used when creating the SIWE message on the client side. Mismatches will cause SIWE message verification to fail.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Implement `verifyMessage` by parsing the incoming `message` to extract `nonce`, `address`, and `chainId`, then pass these explicitly to `validateSiweMessage` along with the expected `domain`.","message":"The `verifyMessage` function on the server side requires robust handling of the SIWE message. Ensure you use a reliable library like `viem/siwe` to parse and validate the message, including checking `domain`, `nonce`, `address`, and `chainId` against expected values to prevent replay attacks and message tampering.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure `minikitClient()` is included in the `plugins` array when calling `createAuthClient({ plugins: [minikitClient()] })`.","cause":"The `minikitClient` plugin was not correctly registered with `createAuthClient`.","error":"TypeError: Cannot read properties of undefined (reading 'minikit')"},{"fix":"Verify your server's `betterAuth` configuration, ensure the `minikit` plugin is added, and check that the endpoint receiving the `getNonce` request is correctly routed and uses the `betterAuth` instance.","cause":"The server-side `betterAuth` instance with the `minikit` plugin is not correctly initialized or accessible, or there's an issue with your `better-auth` setup.","error":"Failed to get nonce: { message: 'Unauthorized', status: 401 }"},{"fix":"Double-check the `getNonce` implementation to ensure it returns a unique, random string and that this exact nonce is passed to `createSiweMessage` on the client and then used by `validateSiweMessage` on the server.","cause":"The nonce generated by the server does not match the nonce included in the SIWE message signed by the client, or the server's `getNonce` and `verifyMessage` implementations are inconsistent.","error":"SIWE message verification failed: Error: Nonce mismatch"},{"fix":"Ensure the `domain` property provided to `minikit({ domain: '...' })` on the server is identical to the `domain` parameter used when creating the SIWE message on the client side.","cause":"The domain specified in the SIWE message signed by the client does not match the `domain` configured in the server-side `minikit` plugin.","error":"SIWE message verification failed: Error: Domain mismatch"}],"ecosystem":"npm","meta_description":null}