Next.js
Integrate Better Auth UI with Next.js
Prerequisites
Make sure you've completed the Quick Start guide first.
Integration
Configure AuthProvider
Configure AuthProvider with Next.js navigation.
"use client"
import { AuthProvider } from "@better-auth-ui/heroui"
import Link from "next/link"
import { useRouter } from "next/navigation"
import { ThemeProvider } from "next-themes"
import type { ReactNode } from "react"
import { RouterProvider } from "react-aria-components"
import { Toaster } from "sonner"
import { authClient } from "@/lib/auth-client"
/**
* Wraps the app UI with theme, routing, authentication, and global toast providers.
*
* @param children - The application UI to render inside the providers
* @returns A React element containing ThemeProvider > RouterProvider > AuthProvider with the provided `children` and a global `Toaster`
*/
export function Providers({ children }: { children: ReactNode }) {
const router = useRouter()
return (
<ThemeProvider attribute="data-theme" defaultTheme="system" enableSystem>
<RouterProvider navigate={router.push}>
<AuthProvider
authClient={authClient}
socialProviders={["google", "github"]}
magicLink
multiSession
navigate={({ href, replace }) =>
replace ? router.replace(href) : router.push(href)
}
Link={Link}
>
{children}
<Toaster />
</AuthProvider>
</RouterProvider>
</ThemeProvider>
)
}The navigate and Link props integrate with Next.js's navigation system. The navigate prop accepts { href, replace } options to handle both push and replace navigation.
Update the Root Layout
Wrap your application with the Providers component in your root layout.
import type { Metadata } from "next"
import { Geist, Geist_Mono } from "next/font/google"
import type { ReactNode } from "react"
import "@/styles/globals.css"
import { Header } from "@/components/header"
import { Providers } from "@/components/providers"
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"]
})
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"]
})
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app"
}
export default function RootLayout({
children
}: Readonly<{
children: ReactNode
}>) {
return (
<html lang="en" suppressHydrationWarning>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<Providers>
<Header />
{children}
</Providers>
</body>
</html>
)
}Create the Auth Page
Create a dynamic auth page that renders the appropriate authentication view based on the path.
import { Auth } from "@better-auth-ui/heroui"
import { viewPaths } from "@better-auth-ui/heroui/core"
import { notFound } from "next/navigation"
export default async function AuthPage({
params
}: {
params: Promise<{
path: string
}>
}) {
const { path } = await params
if (!Object.values(viewPaths.auth).includes(path)) {
notFound()
}
return (
<div className="mx-auto my-auto flex w-full justify-center p-4">
<Auth path={path} />
</div>
)
}The viewPaths.auth object contains all valid auth paths: sign-in, sign-up, sign-out, forgot-password, reset-password, and magic-link.
Protecting Routes
Use the useAuthenticate hook to protect routes and access session data.
"use client"
import { useAuthenticate } from "@better-auth-ui/heroui/react"
import { Spinner } from "@heroui/react"
import Link from "next/link"
export default function Dashboard() {
const { data: sessionData } = useAuthenticate()
if (!sessionData) {
return (
<div className="min-h-svh flex items-center justify-center">
<Spinner color="current" />
</div>
)
}
return (
<div className="min-h-svh flex flex-col items-center justify-center gap-4">
<h1 className="text-2xl">Hello, {sessionData.user.email}</h1>
<Link href="/auth/sign-out">Sign Out</Link>
</div>
)
}The useAuthenticate hook will automatically redirect unauthenticated users to the sign-in page.
Example Project
For a complete working example, check out the next-heroui-example in the repository.
Last updated on