BTST
PluginsQuickstartDocs
Live Blog

From research to product evaluation

Evaluating a publishing workflow for an app you already own?

See what the BTST Blog plugin adds to an existing React or Next.js app
BTST

Open-source TypeScript features for the React application, data, and deployment you already own.

Released plugins

  • Blog
  • AI Chat
  • CMS
  • Form Builder
  • UI Builder
  • Kanban
  • Comments
  • Media
  • Route Docs
  • OpenAPI
  • Better Auth UI

Resources

  • Quickstart
  • Documentation
  • All plugins
  • Live Blog
  • GitHub (opens in a new tab)
© 2026 BTST. Open source under the MIT License.
AI Chat
September 10, 2026AuthNextJS

Better Auth UI in an Existing Next.js App: Routes, Sessions, and Permissions

Connect Better Auth UI to an existing Next.js app while keeping API routes, session refresh, and editorial permissions clear.

Better Auth UI in an Existing Next.js App: Routes, Sessions, and Permissions

You already have a Better Auth server. Sign-in works through its API, but your Next.js app still needs sign-in, recovery, account, and security pages. Before adding a UI package, identify which layer each package will own. That decision determines your routes, session refresh behavior, and permission checks.

This guide covers the BTST v3 companion, @btst/better-auth-ui@2.0.0, in an existing Next.js App Router application. It is a client integration for an application-owned Better Auth backend. The Better Auth UI companion reference documents its supported dependency cohort and generated files.

Keep the three route bases separate#

A typical application has three different addresses:

AddressPurposeOwner
/api/authBetter Auth HTTP handlerYour Better Auth installation
/api/dataBTST business-plugin APIsYour BTST backend stack
/pages/auth/sign-inA rendered sign-in pageThe BTST client stack and companion

Changing the site path to /p changes the companion page URLs to /p/auth/* and /p/account/*. It does not move Better Auth's HTTP handler. A sign-in form posting to the site-page path is a configuration error, even if that page looks correct.

Keep the existing Better Auth server, database, migrations, secrets, and providers. Check its endpoint before debugging the UI. If the backend does not yet exist, finish that integration first using Better Auth's installation documentation.

Choose the companion explicitly#

Run the generator from a clean commit in the existing app and review the generated diff:

BASH
  1. 1
npx @btst/codegen@0.2.0 init --framework nextjs --plugins better-auth-ui

Use the framework installation guide for shared UI and provider prerequisites. The command selects auth and account UI; optional organization, passkey, and API-key behavior still needs deliberate configuration in the matching Better Auth server and browser client. Installing a peer dependency does not activate its runtime feature.

Do not mix examples from older BTST releases into the generated v3 setup. In v3, createClientStack() receives shared API, site, and QueryClient settings. The companion registers through authClientPlugin() and accountClientPlugin() from @btst/better-auth-ui/client.

The browser client factory below targets an existing same-origin Better Auth handler. Create and reuse a browser client in your application's provider wiring; do not construct a new one on every render.

TS
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
import { createAuthClient } from "better-auth/react";

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

If you change basePath, change it to the actual backend handler path. For a separate auth origin, review cookies, allowed origins, and credentials as part of the backend integration; a UI route change alone cannot fix cross-origin session transport.

Refresh server-rendered state after sign-in#

Successful sign-in changes the session used by the browser. Your server-rendered navigation or protected content may still reflect the previous request until Next.js refreshes it.

The companion provider's auth override supports onSessionChange. In the Next.js integration, wire it to router.refresh() using the router from next/navigation. Keep this callback in the client provider. The generated framework wiring is the starting point, especially if your app already has a QueryClient or router provider.

Verify both directions: a signed-out visitor signs in and gains the expected account view; a signed-in visitor signs out and loses protected access. Test a fresh page request as well as navigation inside the app. A stale header and an unauthorized API response are different failures and need different fixes.

Authenticated does not mean authorized to publish#

The UI companion reads the Better Auth session for its own views. Permission to edit Blog posts or CMS content belongs to your business authorization policy. Map your server identity into BTST's authorization contracts separately, using the authorization guide.

For an editorial site, a useful access matrix is:

RequestAnonymousOrdinary memberEditor
Read a published articleAllowAllowAllow
Read a private draftDenyDenyAllow by policy
Create or update a postDenyDenyAllow by policy
Publish or deleteDenyDenyApply the specific editorial permission

Check this matrix against the server endpoints, not only the presence of buttons. Client-side visibility improves usability, but a caller can send an HTTP request without using your page.

Verify the integration before release#

Open the sign-in page directly, complete a real permitted sign-in in a test environment, refresh the account page, and sign out. Confirm recovery and verification links return to the correct application origin. For any optional auth feature, exercise its backend and UI together before advertising it.

Then test a direct unauthorized business-API request. Adding account pages should not expand a user's editorial permissions. If you also publish articles, the Next.js draft and cache guide covers the separate public-content boundary.

Use the companion evaluation page to check fit, then follow the current installation reference for the complete provider configuration and supported package versions.

In This Post

Keep the three route bases separateChoose the companion explicitlyRefresh server-rendered state after sign-inAuthenticated does not mean authorized to publishVerify the integration before release