diff --git a/docs/app/code-block.tsx b/docs/app/code-block.tsx index e5319cc..b57992d 100644 --- a/docs/app/code-block.tsx +++ b/docs/app/code-block.tsx @@ -91,9 +91,6 @@ function CodeBlockInternal({ return Array.from({ length: end - start + 1 }, (_, i) => start + i); }); const sorted = [...expandedLines].sort((a, b) => a - b); - if (lines.some((line) => Array.isArray(line))) { - console.log("sorted", sorted); - } const sections: HighlightedSection[] = []; let current: HighlightedSection = { start: sorted[0], end: sorted[0] }; @@ -106,9 +103,6 @@ function CodeBlockInternal({ } } sections.push(current); - if (lines.some((line) => Array.isArray(line))) { - console.log("sections", sections); - } return sections; }; diff --git a/docs/app/docs-sidebar.tsx b/docs/app/docs-sidebar.tsx index 2324421..392f52b 100644 --- a/docs/app/docs-sidebar.tsx +++ b/docs/app/docs-sidebar.tsx @@ -354,6 +354,18 @@ export default function DocsSidebar({ children }: React.PropsWithChildren) { + + + LLM Instructions + + + + + Next.js + + + + Users table diff --git a/docs/app/page.tsx b/docs/app/page.tsx index b4f7e62..66a5081 100644 --- a/docs/app/page.tsx +++ b/docs/app/page.tsx @@ -9,6 +9,7 @@ import { cx } from "class-variance-authority"; import { GenerateSecret } from "./generate-secret"; import { cn } from "@/lib/utils"; import { useSelectedVariant } from "@/app/code-block-variant-store"; +import ConvexBetterAuthGuideNextjs from "@/components/sections/convex-better-auth-guide-nextjs"; const CodeBlock = (props: ComponentProps) => ( @@ -3036,6 +3037,12 @@ export default function Home() { /> + +
+ + + +
); } diff --git a/docs/components/sections/convex-better-auth-guide-nextjs.tsx b/docs/components/sections/convex-better-auth-guide-nextjs.tsx new file mode 100644 index 0000000..597ac94 --- /dev/null +++ b/docs/components/sections/convex-better-auth-guide-nextjs.tsx @@ -0,0 +1,307 @@ +"use client"; + +import { useState } from "react"; + +export default function ConvexBetterAuthGuideNextjs() { + const [isExpanded, setIsExpanded] = useState(false); + + const guideContent = `### These are steps to setup better auth with convex and nextjs + +# 1. Install the dependencies + +\`\`\`bash +npm install @convex-dev/better-auth +npm install better-auth@1.2.12 --save-exact +npm install convex@latest +\`\`\` + +# 2. Add a convex/auth.config.ts file to configure Better Auth as an authentication provider + +\`\`\`ts +// convex/auth.config.ts +export default { + providers: [ + { + // Your Convex site URL is provided in a system + // environment variable + domain: process.env.CONVEX_SITE_URL, + + // Application ID has to be "convex" + applicationID: "convex", + }, + ], +}; +\`\`\` + +# 3. Add the Better Auth plugin to your Convex app configuration + +\`\`\`ts +// convex/convex.config.ts +import { defineApp } from 'convex/server' +import betterAuth from '@convex-dev/better-auth/convex.config' + +const app = defineApp() +app.use(betterAuth) + +export default app +\`\`\` + +# 4. Generate a secret for encryption and generating hashes. + +TIP: Make sure to check which port your Next.js app is running on (typically 3000) and adjust the BETTER_AUTH_URL accordingly + +\`\`\`bash +npx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32) +npx convex env set BETTER_AUTH_URL=http://localhost:3000 +\`\`\` + +# 5. Add the Convex site URL environment variable to the .env.local file created by npx convex dev. It will be picked up by your framework dev server. + +\`\`\`bash +# Deployment used by \`npx convex dev\` +CONVEX_DEPLOYMENT=dev:adjective-animal-123 # team: team-name, project: project-name + +NEXT_PUBLIC_CONVEX_URL=https://adjective-animal-123.convex.cloud + +# Same as NEXT_PUBLIC_CONVEX_URL but ends in .site +NEXT_PUBLIC_CONVEX_SITE_URL=https://adjective-animal-123.convex.site +\`\`\` + +# 6. First, add a users table to your schema. Name it whatever you like. Better Auth has its own user table that tracks basic user data, so your application user table only needs fields specific to your app (or none at all). + +\`\`\`ts +// convex/schema.ts +import { defineSchema, defineTable } from "convex/server"; + +export default defineSchema({ + users: defineTable({ + // Fields are optional + }), +}); +\`\`\` + +# 7. Create your Better Auth instance. + +\`\`\`ts +// convex/lib/auth.ts +import { convexAdapter } from "@convex-dev/better-auth"; +import { convex } from "@convex-dev/better-auth/plugins"; +import { betterAuth } from "better-auth"; +import { betterAuthComponent } from "../convex/auth"; +import { type GenericCtx } from "../convex/_generated/server"; + +// You'll want to replace this with an environment variable +const siteUrl = "http://localhost:3000"; + +export const createAuth = (ctx: GenericCtx) => + // Configure your Better Auth instance here + betterAuth({ + // All auth requests will be proxied through your next.js server + baseURL: siteUrl, + database: convexAdapter(ctx, betterAuthComponent), + + // Simple non-verified email/password to get started + emailAndPassword: { + enabled: true, + requireEmailVerification: false, + }, + plugins: [ + // The Convex plugin is required + convex(), + ], + }); +\`\`\` + +\`\`\`ts +// convex/auth.ts +import { + BetterAuth, + type AuthFunctions, + type PublicAuthFunctions, +} from "@convex-dev/better-auth"; +import { api, components, internal } from "./_generated/api"; +import { query } from "./_generated/server"; +import type { Id, DataModel } from "./_generated/dataModel"; + +// Typesafe way to pass Convex functions defined in this file +const authFunctions: AuthFunctions = internal.auth; +const publicAuthFunctions: PublicAuthFunctions = api.auth; + +// Initialize the component +export const betterAuthComponent = new BetterAuth(components.betterAuth, { + authFunctions, + publicAuthFunctions, +}); + +// These are required named exports +export const { + createUser, + updateUser, + deleteUser, + createSession, + isAuthenticated, +} = betterAuthComponent.createAuthFunctions({ + // Must create a user and return the user id + onCreateUser: async (ctx, user) => { + return ctx.db.insert("users", {}); + }, + + // Delete the user when they are deleted from Better Auth + onDeleteUser: async (ctx, userId) => { + await ctx.db.delete(userId as Id<"users">); + }, +}); + +// Example function for getting the current user +// Feel free to edit, omit, etc. +export const getCurrentUser = query({ + args: {}, + handler: async (ctx) => { + // Get user data from Better Auth - email, name, image, etc. + const userMetadata = await betterAuthComponent.getAuthUser(ctx); + if (!userMetadata) { + return null; + } + // Get user data from your application's database + // (skip this if you have no fields in your users table schema) + const user = await ctx.db.get(userMetadata.userId as Id<"users">); + return { + ...user, + ...userMetadata, + }; + }, +}); +\`\`\` + +# 8. Create a Better Auth client instance for interacting with the Better Auth server from your client. + +\`\`\`ts +// lib/auth-client.ts +import { createAuthClient } from "better-auth/react"; +import { convexClient } from "@convex-dev/better-auth/client/plugins"; + +export const authClient = createAuthClient({ + plugins: [convexClient()], +}); +\`\`\` + +# 9. Register Better Auth route handlers on your Convex deployment. + +\`\`\`ts +import { httpRouter } from "convex/server"; +import { betterAuthComponent } from "./auth"; +import { createAuth } from "../lib/auth"; + +const http = httpRouter(); + +betterAuthComponent.registerRoutes(http, createAuth); + +export default http; +\`\`\` + +# 10. Set up route handlers to proxy auth requests from your framework server to your Convex deployment. + +\`\`\`ts +import { nextJsHandler } from "@convex-dev/better-auth/nextjs"; + +export const { GET, POST } = nextJsHandler(); +\`\`\` + +# 11. Wrap your app with the ConvexBetterAuthProvider component. + +\`\`\`ts +"use client"; + +import { ReactNode } from "react"; +import { ConvexReactClient } from "convex/react"; +import { authClient } from "@/lib/auth-client"; +import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react"; + +const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); + +export function ConvexClientProvider({ children }: { children: ReactNode }) { + return ( + + {children} + + ); +} +\`\`\``; + + const previewContent = `### These are steps to setup better auth with convex and nextjs + +# 1. Install the dependencies + +\`\`\`bash +npm install @convex-dev/better-auth +npm install better-auth@1.2.12 --save-exact +npm install convex@latest +\`\`\` + +# 2. Add a convex/auth.config.ts file to configure Better Auth... + +... and 9 more steps`; + + return ( +
+
+

LLM Instructions: Convex Better Auth Setup (Next.js)

+

+ Copy and paste these instructions to any LLM (Claude code, Cursor, Windsurf, etc.) to set up better auth with convex. +

+
+ +
+ {/* Header with toggle and copy button */} +
+ + + +
+ + {/* Content */} +
+
+            
+              {isExpanded ? guideContent : previewContent}
+            
+          
+ + {!isExpanded && ( +
+ )} +
+ + {/* Footer when collapsed */} + {!isExpanded && ( +
+ +
+ )} +
+
+ ); +}