BTST

Better Auth UI Companion

Add Better Auth UI pages and optional feature plugins to an application that already runs Better Auth.

Client-onlyCompanionReleased · Preview

Best for

Teams already operating Better Auth that want its auth and account UI composed into the maintained BTST framework paths.

Add auth and account routes to a BTST client stack that already has a Better Auth backend.

BTST supplies

  • Auth and account route definitions backed by @btst/better-auth-ui
  • Sign-in, sign-up, recovery, account, security, and settings UI
  • A CLI scaffold that creates one browser client for the existing auth endpoint
  • Framework-native session refresh wiring for the maintained integration paths

You supply

  • An existing Better Auth server, schema, migrations, providers, and secrets
  • A Better Auth browser client configured for the adopter-owned endpoint
  • Any optional Better Auth server and client plugins used by the application
  • Deployment, session policy, and separate BTST authorization mapping when needed

You own and customize

Your application keeps the Better Auth server, database, providers, secrets, sessions, and deployment. The companion supplies client routes and UI; it does not create or host authentication.

Compatibility and dependencies

Maintained: Next.js 15+ App Router, React Router v7, TanStack Start.

Requires: An existing Better Auth backend and browser client; The supported @btst/better-auth-ui and Better Auth package cohort.

External services: The adopter's existing Better Auth endpoint; BTST does not host it.

From registration to result

A semantic workflow, not a setup shortcut

  1. 1Operate Better Auth

    Keep the existing server endpoint, schema, providers, secrets, and browser client.

  2. 2Add the companion

    Register auth and account client plugins in the BTST client stack.

  3. 3Mount routes

    Serve sign-in, recovery, account, security, and settings views under your site path.

  4. 4Refresh sessions

    Use the generated framework-native refresh seam after session changes.

@btst/better-auth-ui is the separately maintained Better Auth UI plugin package for BTST v4. It adds resolved auth, account, organization, and admin routes while Better Auth UI continues to read its own session and native permissions from your Better Auth client.

This integration assumes your application already owns a Better Auth server endpoint. It does not generate a Better Auth backend, database adapter, schema, migrations, authentication providers, secrets, or deployment configuration.

Generate the minimal integration

Select the companion explicitly; it is never part of the default scaffold.

npx @btst/codegen init --plugins better-auth-ui

The generated result:

  • registers only authClientPlugin() and accountClientPlugin();
  • creates one browser client for the existing /api/auth endpoint;
  • mounts routes under the resolved BTST site path (/pages/auth/* and /pages/account/* by default);
  • configures API, site, and QueryClient runtime only once in createClientStack(); and
  • refreshes the framework explicitly after a Better Auth session change.

Organization, admin, API-key, passkey, multi-session, billing, and other Better Auth extensions remain opt-in. Configure the matching Better Auth server and client plugins before enabling their UI. The default generated scaffold remains auth and account only.

Supported release cohort

@btst/better-auth-ui@3.0.1 packages the React/shadcn components from upstream Better Auth UI 1.7.26. Install it with the BTST v4 cohort:

PackageVersion
@btst/stack, @btst/codegen4.5.1
@btst/better-auth-ui3.0.1
better-auth, @better-auth/core1.7.6
@better-auth/api-key, @better-auth/passkey1.7.6
@better-auth/utils0.4.2
@better-fetch/fetch1.3.2
better-call1.4.0
@btst/db and BTST database adapters3.0.0
React and React DOM>=19.2.6
Tailwind CSS>=4.3.2
@tanstack/react-query, @tanstack/query-core5.102.0 (tested cohort)

For a manual installation, add the companion and exact auth cohort alongside your existing BTST dependencies:

pnpm add --save-exact @btst/better-auth-ui@3.0.1 \
  @tanstack/react-query@5.102.0 @tanstack/query-core@5.102.0 \
  better-auth@1.7.6 @better-auth/core@1.7.6 \
  @better-auth/api-key@1.7.6 @better-auth/passkey@1.7.6 \
  @better-auth/utils@0.4.2 @better-fetch/fetch@1.3.2 better-call@1.4.0

API-key and passkey packages provide upstream type declarations; installing them does not enable their server or client features. Component dependencies are included in the companion package. Resolve remaining peer requirements against its published manifest. The direct cohort above must remain aligned. Upstream agent-auth and better-call also install their own supported versions of better-call and @better-auth/utils; those nested implementation dependencies can coexist and should not be forced to the application's direct versions.

Browser client and resolved routes

The CLI generates the following application-owned seam:

lib/auth-client.ts
import { createAuthClient } from "better-auth/react"

export function createAppAuthClient(baseURL?: string) {
  return createAuthClient({
    ...(baseURL ? { baseURL } : {}),
    basePath: "/api/auth",
  })
}

Change basePath only when your existing Better Auth handler uses a different path. The companion route bases are not configured here: they derive from the site runtime passed once to createClientStack().

lib/stack-client.tsx
import { accountClientPlugin, authClientPlugin } from "@btst/better-auth-ui/client"
import { createClientStack } from "@btst/stack/client"

return createClientStack({
  api: { baseURL: apiOrigin, basePath: "/api/data" },
  site: { baseURL: siteOrigin, basePath: "/pages" },
  queryClient,
  plugins: {
    auth: authClientPlugin(),
    account: accountClientPlugin(),
  },
})

Provider overrides

The resolved stack infers plugin override keys. Configure the Better Auth client and upstream feature plugins once under auth. Account routes do not require an account: true flag.

<StackProvider
  stack={browserStack}
  router={frameworkRouter}
  overrides={{
    auth: {
      authClient,
      redirectTo: "/pages/account/account",
      onSessionChange: refreshThroughTheFramework,
    },
  }}
>
  {children}
</StackProvider>

Use the framework-native synchronization generated for your target:

onSessionChange: () => router.refresh()
onSessionChange: () => revalidator.revalidate()
onSessionChange: () => router.invalidate()

The bridge performs no hidden BTST identity refetch. If business plugins use BTST authorization, map the Better Auth session separately with BTST's generic createClientAuth and createServerAuth contracts and keep server authorization authoritative.

Optional feature families

The package includes upstream auth methods (phone, wallet, device, and agent authorization), admin pages, organization management, audit logs, SSO, OAuth client management and consent, and billing. Register organizationClientPlugin() or adminClientPlugin() in the BTST client stack when those route families are needed. Enable their upstream UI feature plugins through overrides.auth.plugins. Only configured views render; disabled feature routes do not request feature data.

BTST supplies the components, pages, routing, notifications, localization, and shared query client. Applications configure the matching Better Auth backend plugins, external providers and credentials, and authorization rules. In particular, an admin page does not grant admin access; the Better Auth backend continues to enforce permissions.

Migrating from companion v2

  • Update the complete dependency cohort above, including React and Tailwind.
  • Keep the authClientPlugin(), accountClientPlugin(), and organizationClientPlugin() registration pattern.
  • Move flat feature flags into upstream UI plugins in overrides.auth.plugins.
  • Replace overrides.auth.emailVerification: true with overrides.auth.emailAndPassword: { requireEmailVerification: true } when email/password sign-up requires verification. Keep the matching native Better Auth server requirement and email delivery configuration; the UI flag controls the post-sign-up destination, while the server enforces access.
  • Remove account: true from provider overrides.
  • The default account settings URL changes from /pages/account/settings to /pages/account/account. Preserve existing links by setting overrides.auth.viewPaths.settings.account to "settings", or update links to the new default (adjust /pages for the configured site mount).
  • Use upstream Auth, Settings, Organization, and Admin components when embedding UI directly. See the companion migration guide for feature-specific configuration and removed component names.

For an existing application that keeps /pages/account/settings, use the same view path in its BTST auth overrides and any standalone AuthProvider that renders account links, such as a header UserButton:

const viewPaths = {
  settings: { account: "settings" },
  auth: { verifyEmail: "email-verification" },
}

// Pass as StackProvider's overrides.auth.
const authOverrides = {
  authClient,
  viewPaths,
  redirectTo: "/pages/account/settings",
  onSessionChange: refreshThroughTheFramework,
}

The auth mapping preserves /pages/auth/email-verification; its new default is /pages/auth/verify-email.

Page overrides use the configured URL segment too: with this mapping, account page props belong under overrides.account.pageProps["settings"].