Better Auth UI Plugin (Beta)
Beautiful shadcn/ui authentication components for better-auth
The Better Auth UI plugin provides beautiful, plug-and-play authentication UI components built with shadcn/ui for better-auth. This is a fork of the popular better-auth-ui library, adapted for seamless integration with Better Stack.
Features
- Sign In / Sign Up – Complete authentication flows with email, password, social login, and magic links
- Account Management – User profile settings, password changes, and account deletion
- Two-Factor Authentication – TOTP and OTP support for enhanced security
- Social Login – GitHub, Google, Discord, and more OAuth providers
- Passkeys – WebAuthn/Passkey authentication support
- Organizations – Team and organization management with invitations and roles
- Fully Customizable – Built with TailwindCSS and shadcn/ui for easy styling
Installation
Before starting, ensure you have:
- A Next.js project with
@btst/stackalready set up (see Installation) better-authconfigured (server-side auth)- A
better-authclient (lib/auth-client.ts) set up - A database adapter (e.g., Drizzle with
@btst/adapter-drizzle)
1. Install the Package
pnpm add @btst/better-auth-uiOr with npm/yarn:
npm install @btst/better-auth-ui
# or
yarn add @btst/better-auth-ui2. Configure the Stack Client (Server-Side)
Import and register the auth plugins in your better-stack-client.tsx file:
import { createStackClient } from "@btst/stack/client"
import {
authClientPlugin,
accountClientPlugin,
organizationClientPlugin
} from "@btst/better-auth-ui/client"
import { QueryClient } from "@tanstack/react-query"
const getBaseURL = () =>
process.env.BASE_URL || "http://localhost:3000"
export function getStackClient(queryClient: QueryClient, options?: { headers?: Headers }) {
const baseURL = getBaseURL()
return createStackClient({
plugins: {
// Auth plugin - handles sign-in, sign-up, forgot-password, etc.
auth: authClientPlugin({
siteBaseURL: baseURL,
siteBasePath: "/p", // Your base path for routes
}),
// Account plugin - handles settings, profile management
account: accountClientPlugin({
siteBaseURL: baseURL,
siteBasePath: "/p",
}),
// Organization plugin - handles team/org management
organization: organizationClientPlugin({
siteBaseURL: baseURL,
siteBasePath: "/p",
}),
// ... other plugins (blog, cms, etc.)
},
})
}3. Configure the BetterStackProvider (Client-Side Layout)
Configure the plugin overrides in your catch-all layout file:
"use client"
import { BetterStackProvider } from "@btst/stack/context"
import type {
AuthPluginOverrides,
AccountPluginOverrides,
OrganizationPluginOverrides
} from "@btst/better-auth-ui/client"
import { authClient } from "@/lib/auth-client"
import Link from "next/link"
import { useRouter } from "next/navigation"
import type { ReactNode } from "react"
type PluginOverrides = {
auth: AuthPluginOverrides
account: AccountPluginOverrides
organization: OrganizationPluginOverrides
}
export default function PagesLayout({ children }: { children: ReactNode }) {
const router = useRouter()
// Shared auth configuration
const authConfig = {
authClient: authClient, // Your better-auth client
navigate: router.push, // Navigation function
replace: router.replace, // Replace navigation
onSessionChange: () => router.refresh(), // Refresh on session change
Link: Link, // Next.js Link component
}
return (
<BetterStackProvider<PluginOverrides>
basePath="/p"
overrides={{
auth: {
...authConfig,
basePath: "/p/auth", // Auth routes base path
redirectTo: "/p/account/settings", // Where to redirect after login
// Optional features:
// social: { providers: ["github", "google"] },
// magicLink: true,
// passkey: true,
// twoFactor: ["otp", "totp"],
},
account: {
...authConfig,
basePath: "/p/account", // Account routes base path
account: {
fields: ["image", "name"], // Editable profile fields
},
// Optional: Enable avatar upload
// avatar: {
// upload: async (file) => {
// const blob = await uploadImage(file);
// return blob.url;
// },
// size: 128,
// extension: "png",
// },
// Optional: Allow account deletion
// deleteUser: true,
},
organization: {
...authConfig,
basePath: "/p/org", // Organization routes base path
},
}}
>
{children}
</BetterStackProvider>
)
}4. Import Required CSS
Add the better-auth-ui styles to your global stylesheet:
@import "@btst/better-auth-ui/css";Available Routes
Once configured, the following routes become available:
Auth Routes
| Route | Description |
|---|---|
/p/auth/sign-in | Sign in page |
/p/auth/sign-up | Sign up page |
/p/auth/forgot-password | Password reset request |
/p/auth/reset-password | Password reset form |
/p/auth/callback | OAuth callback handler |
Account Routes
| Route | Description |
|---|---|
/p/account/settings | User settings page |
/p/account/security | Security settings (password, 2FA) |
Organization Routes
| Route | Description |
|---|---|
/p/org | Organization dashboard |
/p/org/create | Create new organization |
/p/org/settings | Organization settings |
/p/org/members | Team member management |
/p/org/invitations | Pending invitations |
Routes are prefixed with your configured basePath. The examples above use /p as the base path.
Configuration Options
Social Login
Enable social login providers:
auth: {
...authConfig,
social: {
providers: ["github", "google", "discord"]
},
}Magic Link
Enable passwordless authentication via email:
auth: {
...authConfig,
magicLink: true,
}Two-Factor Authentication
Enable 2FA with OTP or TOTP:
auth: {
...authConfig,
twoFactor: ["otp", "totp"],
}Passkeys
Enable WebAuthn/Passkey authentication:
auth: {
...authConfig,
passkey: true,
}Avatar Upload
Enable avatar upload in account settings:
account: {
...authConfig,
avatar: {
upload: async (file) => {
// Your upload logic - return the URL
const blob = await uploadImage(file);
return blob.url;
},
size: 128,
extension: "png",
},
}Account Deletion
Allow users to delete their accounts:
account: {
...authConfig,
deleteUser: true,
}Organizations
Enable team and organization management:
import { organizationClientPlugin } from "@btst/better-auth-ui/client"
// In your plugins config:
organization: organizationClientPlugin({
siteBaseURL: baseURL,
siteBasePath: "/p",
context: {
// Optional: Pass additional context to organization routes
},
}),Configure organization overrides in the provider:
organization: {
...authConfig,
basePath: "/p/org",
// Organization-specific options
logo: true, // Enable organization logo upload
customRoles: [
{ role: "editor", label: "Editor" },
{ role: "viewer", label: "Viewer" },
],
apiKey: false, // Enable API key support for organizations
pathMode: "default", // or "slug" for slug-based URLs
// slug: "my-org", // Current organization slug (when using pathMode: "slug")
// personalPath: "/dashboard", // Redirect path when Personal Account is selected
}Learn More
For comprehensive documentation on all configuration options, customization, and advanced features, visit:
- Better Auth UI Documentation – Official documentation with demos and guides
- GitHub Repository (Fork) – Source code for the Better Stack fork
- Original Repository – Upstream repository with 1.4k+ stars
- better-auth Documentation – Documentation for the underlying auth library
