diff --git a/docs/base-account/framework-integrations/wagmi/setup.mdx b/docs/base-account/framework-integrations/wagmi/setup.mdx index cd96ec631..72f42cccd 100644 --- a/docs/base-account/framework-integrations/wagmi/setup.mdx +++ b/docs/base-account/framework-integrations/wagmi/setup.mdx @@ -334,10 +334,8 @@ export function SignInWithBase({ connector }: SignInWithBaseProps) { const provider = await connector.getProvider(); if (provider) { try { - // Generate a fresh nonce (this will be overwritten with the backend nonce) - const clientNonce = - Math.random().toString(36).substring(2, 15) + - Math.random().toString(36).substring(2, 15); + // Generate a cryptographically secure nonce + const clientNonce = crypto.randomUUID().replace(/-/g, ''); console.log("clientNonce", clientNonce); // Connect with SIWE to get signature, message, and address const accounts = await (provider as any).request({ diff --git a/docs/base-account/guides/authenticate-users.mdx b/docs/base-account/guides/authenticate-users.mdx index 7a8332200..5658dab32 100644 --- a/docs/base-account/guides/authenticate-users.mdx +++ b/docs/base-account/guides/authenticate-users.mdx @@ -146,13 +146,22 @@ try { ``` ```ts Backend (Viem) import { createPublicClient, http } from 'viem'; +import { verifySiweMessage } from 'viem/siwe'; import { base } from 'viem/chains'; const client = createPublicClient({ chain: base, transport: http() }); export async function verifySig(req, res) { const { address, message, signature } = req.body; - const valid = await client.verifyMessage({ address, message, signature }); + + // Verify SIWE message with domain validation + const valid = await verifySiweMessage(client, { + address, + message, + signature, + domain: 'yourapp.com', // Replace with your actual domain + }); + if (!valid) return res.status(401).json({ error: 'Invalid signature' }); // create session / JWT res.json({ ok: true }); @@ -184,6 +193,7 @@ export async function verifySig(req, res) { import crypto from "crypto"; import express from "express"; import { createPublicClient, http } from "viem"; +import { verifySiweMessage } from "viem/siwe"; import { base } from "viem/chains"; const app = express(); @@ -209,8 +219,15 @@ app.post("/auth/verify", async (req, res) => { return res.status(400).json({ error: "Invalid or reused nonce" }); } - // 2. Verify signature - const valid = await client.verifyMessage({ address, message, signature }); + // 2. Verify SIWE signature with domain validation (prevents cross-domain replay attacks) + const valid = await verifySiweMessage(client, { + address, + message, + signature, + domain: 'yourapp.com', // Replace with your actual domain + nonce, // verifySiweMessage validates nonce is in the message + }); + if (!valid) return res.status(401).json({ error: "Invalid signature" }); // 3. Create session / JWT here diff --git a/docs/base-account/guides/sign-and-verify-typed-data.mdx b/docs/base-account/guides/sign-and-verify-typed-data.mdx index 180fb15ec..3b662791e 100644 --- a/docs/base-account/guides/sign-and-verify-typed-data.mdx +++ b/docs/base-account/guides/sign-and-verify-typed-data.mdx @@ -190,7 +190,7 @@ const usedNonces = new Set(); app.get('/typed-data/prepare', (req, res) => { const { userAddress, action, resource } = req.query; - const nonce = Math.floor(Math.random() * 1000000); + const nonce = crypto.randomBytes(16).toString('hex'); const expiry = Math.floor(Date.now() / 1000) + 3600; // 1 hour const typedData = { diff --git a/docs/base-account/reference/ui-elements/sign-in-with-base-button.mdx b/docs/base-account/reference/ui-elements/sign-in-with-base-button.mdx index 03809c855..fa260a596 100644 --- a/docs/base-account/reference/ui-elements/sign-in-with-base-button.mdx +++ b/docs/base-account/reference/ui-elements/sign-in-with-base-button.mdx @@ -325,7 +325,7 @@ const handleSignInWithSIWE = async () => { address: account, chainId: base.id, domain: window.location.host, - nonce: Math.random().toString(36).substring(7), + nonce: crypto.randomUUID().replace(/-/g, ''), uri: window.location.origin, version: '1', statement: 'Sign in to MyApp with your Base Account'