# Advanced Features Better Auth plugins extend functionality beyond basic authentication. ## Two-Factor Authentication ### Server Setup ```ts import { betterAuth } from "better-auth"; import { twoFactor } from "better-auth/plugins"; export const auth = betterAuth({ plugins: [ twoFactor({ issuer: "YourAppName", // TOTP issuer name otpOptions: { period: 30, // OTP validity period (seconds) digits: 6, // OTP length } }) ] }); ``` ### Client Setup ```ts import { createAuthClient } from "better-auth/client"; import { twoFactorClient } from "better-auth/client/plugins"; export const authClient = createAuthClient({ plugins: [ twoFactorClient({ twoFactorPage: "/two-factor", // Redirect to 2FA verification page redirect: true // Auto-redirect if 2FA required }) ] }); ``` ### Enable 2FA for User ```ts // Enable TOTP const { data } = await authClient.twoFactor.enable({ password: "userPassword" // Verify user identity }); // data contains QR code URI for authenticator app const qrCodeUri = data.totpURI; const backupCodes = data.backupCodes; // Save these securely ``` ### Verify TOTP Code ```ts await authClient.twoFactor.verifyTOTP({ code: "123456", trustDevice: true // Skip 2FA on this device for 30 days }); ``` ### Disable 2FA ```ts await authClient.twoFactor.disable({ password: "userPassword" }); ``` ### Backup Codes ```ts // Generate new backup codes const { data } = await authClient.twoFactor.generateBackupCodes({ password: "userPassword" }); // Use backup code instead of TOTP await authClient.twoFactor.verifyBackupCode({ code: "backup-code-123" }); ``` ## Passkeys (WebAuthn) ### Server Setup ```ts import { betterAuth } from "better-auth"; import { passkey } from "better-auth/plugins"; export const auth = betterAuth({ plugins: [ passkey({ rpName: "YourApp", // Relying Party name rpID: "yourdomain.com" // Your domain }) ] }); ``` ### Client Setup ```ts import { createAuthClient } from "better-auth/client"; import { passkeyClient } from "better-auth/client/plugins"; export const authClient = createAuthClient({ plugins: [passkeyClient()] }); ``` ### Register Passkey ```ts // User must be authenticated first await authClient.passkey.register({ name: "My Laptop" // Optional: name for this passkey }); ``` ### Sign In with Passkey ```ts await authClient.passkey.signIn(); ``` ### List User Passkeys ```ts const { data } = await authClient.passkey.list(); // data contains array of registered passkeys ``` ### Delete Passkey ```ts await authClient.passkey.delete({ id: "passkey-id" }); ``` ## Magic Link ### Server Setup ```ts import { betterAuth } from "better-auth"; import { magicLink } from "better-auth/plugins"; export const auth = betterAuth({ plugins: [ magicLink({ sendMagicLink: async ({ email, url, token }) => { await sendEmail({ to: email, subject: "Sign in to YourApp", html: `Click here to sign in.` }); }, expiresIn: 300, // Link expires in 5 minutes (seconds) }) ] }); ``` ### Client Setup ```ts import { createAuthClient } from "better-auth/client"; import { magicLinkClient } from "better-auth/client/plugins"; export const authClient = createAuthClient({ plugins: [magicLinkClient()] }); ``` ### Send Magic Link ```ts await authClient.magicLink.sendMagicLink({ email: "user@example.com", callbackURL: "/dashboard" }); ``` ### Verify Magic Link ```ts // Called automatically when user clicks link // Token in URL query params handled by Better Auth await authClient.magicLink.verify({ token: "token-from-url" }); ``` ## Organizations (Multi-Tenancy) ### Server Setup ```ts import { betterAuth } from "better-auth"; import { organization } from "better-auth/plugins"; export const auth = betterAuth({ plugins: [ organization({ allowUserToCreateOrganization: true, organizationLimit: 5, // Max orgs per user creatorRole: "owner" // Role for org creator }) ] }); ``` ### Client Setup ```ts import { createAuthClient } from "better-auth/client"; import { organizationClient } from "better-auth/client/plugins"; export const authClient = createAuthClient({ plugins: [organizationClient()] }); ``` ### Create Organization ```ts await authClient.organization.create({ name: "Acme Corp", slug: "acme", // Unique slug metadata: { industry: "Technology" } }); ``` ### Invite Members ```ts await authClient.organization.inviteMember({ organizationId: "org-id", email: "user@example.com", role: "member", // owner, admin, member message: "Join our team!" // Optional }); ``` ### Accept Invitation ```ts await authClient.organization.acceptInvitation({ invitationId: "invitation-id" }); ``` ### List Organizations ```ts const { data } = await authClient.organization.list(); // Returns user's organizations ``` ### Update Member Role ```ts await authClient.organization.updateMemberRole({ organizationId: "org-id", userId: "user-id", role: "admin" }); ``` ### Remove Member ```ts await authClient.organization.removeMember({ organizationId: "org-id", userId: "user-id" }); ``` ### Delete Organization ```ts await authClient.organization.delete({ organizationId: "org-id" }); ``` ## Session Management ### Configure Session Expiration ```ts export const auth = betterAuth({ session: { expiresIn: 60 * 60 * 24 * 7, // 7 days (seconds) updateAge: 60 * 60 * 24, // Update session every 24 hours cookieCache: { enabled: true, maxAge: 5 * 60 // Cache for 5 minutes } } }); ``` ### Server-Side Session ```ts // Next.js import { auth } from "@/lib/auth"; import { headers } from "next/headers"; const session = await auth.api.getSession({ headers: await headers() }); if (!session) { // Not authenticated } ``` ### Client-Side Session ```tsx // React import { authClient } from "@/lib/auth-client"; function UserProfile() { const { data: session, isPending, error } = authClient.useSession(); if (isPending) return