neon-auth-nextjs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Neon Auth for Next.js

适用于Next.js的Neon Auth

Help developers set up @neondatabase/auth in Next.js App Router applications (auth only, no database).
帮助开发者在Next.js App Router应用中配置@neondatabase/auth(仅认证功能,无需数据库)。

When to Use

适用场景

Use this skill when:
  • Setting up Neon Auth in Next.js (App Router)
  • User mentions "next.js", "next", or "app router" with Neon Auth
  • Auth-only setup (no database needed)
在以下场景中使用本指南:
  • 在Next.js(App Router)中配置Neon Auth
  • 用户提及"next.js"、"next"或"app router"并关联Neon Auth
  • 仅需认证功能的场景(无需数据库)

Critical Rules

核心规则

  1. Server vs Client imports: Use correct import paths
  2. 'use client'
    directive
    : Required for client components using hooks
  3. CSS Import: Choose ONE - either
    /ui/css
    OR
    /ui/tailwind
    , never both
  4. onSessionChange: Always call
    router.refresh()
    to update Server Components
  1. 服务器端与客户端导入:使用正确的导入路径
  2. 'use client'
    指令
    :使用hooks的客户端组件必须添加该指令
  3. CSS导入:二选一 - 要么导入
    /ui/css
    ,要么导入
    /ui/tailwind
    ,切勿同时导入两者
  4. onSessionChange:必须调用
    router.refresh()
    以更新服务器组件

Critical Imports

核心导入项

PurposeImport From
Unified Server (
createNeonAuth
)
@neondatabase/auth/next/server
Client Auth
@neondatabase/auth/next
UI Components
@neondatabase/auth/react/ui
View Paths (static params)
@neondatabase/auth/react/ui/server
Note: Use
createNeonAuth()
from
@neondatabase/auth/next/server
to get a unified
auth
instance that provides:
  • .handler()
    - API route handler
  • .middleware()
    - Route protection middleware
  • All Better Auth server methods (
    .signIn
    ,
    .signUp
    ,
    .getSession
    , etc.)

用途导入来源
统一服务器端(
createNeonAuth
@neondatabase/auth/next/server
客户端认证
@neondatabase/auth/next
UI组件
@neondatabase/auth/react/ui
视图路径(静态参数)
@neondatabase/auth/react/ui/server
注意:从
@neondatabase/auth/next/server
中使用
createNeonAuth()
获取统一的
auth
实例,该实例提供:
  • .handler()
    - API路由处理器
  • .middleware()
    - 路由保护中间件
  • 所有Better Auth服务器端方法(
    .signIn
    ,
    .signUp
    ,
    .getSession
    等)

Setup

配置步骤

1. Install

1. 安装

bash
npm install @neondatabase/auth
bash
npm install @neondatabase/auth

2. Environment (
.env.local
)

2. 环境配置(
.env.local

NEON_AUTH_BASE_URL=https://your-auth.neon.tech
NEON_AUTH_COOKIE_SECRET=your-secret-at-least-32-characters-long
Important: Generate a secure secret (32+ characters) for production:
bash
openssl rand -base64 32
NEON_AUTH_BASE_URL=https://your-auth.neon.tech
NEON_AUTH_COOKIE_SECRET=your-secret-at-least-32-characters-long
重要提示:为生产环境生成一个安全的密钥(至少32个字符):
bash
openssl rand -base64 32

3. Server Setup (
lib/auth/server.ts
)

3. 服务器端配置(
lib/auth/server.ts

Create a auth instance that provides handler, middleware, and server methods:
typescript
import { createNeonAuth } from '@neondatabase/auth/next/server';

export const auth = createNeonAuth({
  baseUrl: process.env.NEON_AUTH_BASE_URL!,
  cookies: {
    secret: process.env.NEON_AUTH_COOKIE_SECRET!,
    sessionDataTtl: 300,          // Optional: session data cache TTL in seconds (default: 300 = 5 min)
    domain: '.example.com',       // Optional: for cross-subdomain cookies
  },
});
创建一个提供处理器、中间件和服务器端方法的auth实例:
typescript
import { createNeonAuth } from '@neondatabase/auth/next/server';

export const auth = createNeonAuth({
  baseUrl: process.env.NEON_AUTH_BASE_URL!,
  cookies: {
    secret: process.env.NEON_AUTH_COOKIE_SECRET!,
    sessionDataTtl: 300,          // 可选:会话数据缓存过期时间(秒),默认值:300 = 5分钟
    domain: '.example.com',       // 可选:用于跨子域名共享Cookie
  },
});

4. API Route (
app/api/auth/[...path]/route.ts
)

4. API路由(
app/api/auth/[...path]/route.ts

typescript
import { auth } from '@/lib/auth/server';

export const { GET, POST } = auth.handler();
typescript
import { auth } from '@/lib/auth/server';

export const { GET, POST } = auth.handler();

5. Middleware (
middleware.ts
)

5. 中间件(
middleware.ts

typescript
import { auth } from '@/lib/auth/server';

export default auth.middleware({
  loginUrl: '/auth/sign-in',
});

export const config = {
  matcher: ['/dashboard/:path*', '/account/:path*'],
};
typescript
import { auth } from '@/lib/auth/server';

export default auth.middleware({
  loginUrl: '/auth/sign-in',
});

export const config = {
  matcher: ['/dashboard/:path*', '/account/:path*'],
};

6. Client (
lib/auth/client.ts
)

6. 客户端配置(
lib/auth/client.ts

typescript
'use client';
import { createAuthClient } from '@neondatabase/auth/next';

export const authClient = createAuthClient();
typescript
'use client';
import { createAuthClient } from '@neondatabase/auth/next';

export const authClient = createAuthClient();

7. Provider (
app/providers.tsx
)

7. 提供者组件(
app/providers.tsx

typescript
'use client';
import { NeonAuthUIProvider } from '@neondatabase/auth/react/ui';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { authClient } from '@/lib/auth/client';

export function Providers({ children }: { children: React.ReactNode }) {
  const router = useRouter();

  return (
    <NeonAuthUIProvider
      authClient={authClient}
      navigate={router.push}
      replace={router.replace}
      onSessionChange={() => router.refresh()}
      redirectTo="/dashboard"
      Link={({href, children}) => <Link to={href}>{children}</Link>}
    >
      {children}
    </NeonAuthUIProvider>
  );
}
typescript
'use client';
import { NeonAuthUIProvider } from '@neondatabase/auth/react/ui';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { authClient } from '@/lib/auth/client';

export function Providers({ children }: { children: React.ReactNode }) {
  const router = useRouter();

  return (
    <NeonAuthUIProvider
      authClient={authClient}
      navigate={router.push}
      replace={router.replace}
      onSessionChange={() => router.refresh()}
      redirectTo="/dashboard"
      Link={({href, children}) => <Link to={href}>{children}</Link>}
    >
      {children}
    </NeonAuthUIProvider>
  );
}

8. Layout (
app/layout.tsx
)

8. 布局文件(
app/layout.tsx

typescript
import { Providers } from './providers';
import '@neondatabase/auth/ui/css';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
typescript
import { Providers } from './providers';
import '@neondatabase/auth/ui/css';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

9. Auth Pages (
app/auth/[path]/page.tsx
)

9. 认证页面(
app/auth/[path]/page.tsx

typescript
import { AuthView } from '@neondatabase/auth/react/ui';
import { authViewPaths } from '@neondatabase/auth/react/ui/server';

export function generateStaticParams() {
  return Object.values(authViewPaths).map((path) => ({ path }));
}

export default async function AuthPage({ params }: { params: Promise<{ path: string }> }) {
  const { path } = await params;
  return <AuthView pathname={path} />;
}

typescript
import { AuthView } from '@neondatabase/auth/react/ui';
import { authViewPaths } from '@neondatabase/auth/react/ui/server';

export function generateStaticParams() {
  return Object.values(authViewPaths).map((path) => ({ path }));
}

export default async function AuthPage({ params }: { params: Promise<{ path: string }> }) {
  const { path } = await params;
  return <AuthView pathname={path} />;
}

CSS & Styling

CSS与样式

Import Options

导入选项

Without Tailwind (pre-built CSS bundle ~47KB):
typescript
// app/layout.tsx
import '@neondatabase/auth/ui/css';
With Tailwind CSS v4 (
app/globals.css
):
css
@import 'tailwindcss';
@import '@neondatabase/auth/ui/tailwind';
IMPORTANT: Never import both - causes duplicate styles.
不使用Tailwind(预构建CSS包约47KB):
typescript
// app/layout.tsx
import '@neondatabase/auth/ui/css';
使用Tailwind CSS v4
app/globals.css
):
css
@import 'tailwindcss';
@import '@neondatabase/auth/ui/tailwind';
重要提示:切勿同时导入两者,否则会导致样式重复。

Dark Mode

深色模式

The provider includes
next-themes
. Control via
defaultTheme
prop:
typescript
<NeonAuthUIProvider
  defaultTheme="system" // 'light' | 'dark' | 'system'
  // ...
>
提供者组件集成了
next-themes
。可通过
defaultTheme
属性控制:
typescript
<NeonAuthUIProvider
  defaultTheme="system" // 可选值:'light' | 'dark' | 'system'
  // ...
>

Custom Theming

自定义主题

Override CSS variables in
globals.css
:
css
:root {
  --primary: hsl(221.2 83.2% 53.3%);
  --primary-foreground: hsl(210 40% 98%);
  --background: hsl(0 0% 100%);
  --foreground: hsl(222.2 84% 4.9%);
  --card: hsl(0 0% 100%);
  --card-foreground: hsl(222.2 84% 4.9%);
  --border: hsl(214.3 31.8% 91.4%);
  --input: hsl(214.3 31.8% 91.4%);
  --ring: hsl(221.2 83.2% 53.3%);
  --radius: 0.5rem;
}

.dark {
  --background: hsl(222.2 84% 4.9%);
  --foreground: hsl(210 40% 98%);
  /* ... dark mode overrides */
}

globals.css
中覆盖CSS变量:
css
:root {
  --primary: hsl(221.2 83.2% 53.3%);
  --primary-foreground: hsl(210 40% 98%);
  --background: hsl(0 0% 100%);
  --foreground: hsl(222.2 84% 4.9%);
  --card: hsl(0 0% 100%);
  --card-foreground: hsl(222.2 84% 4.9%);
  --border: hsl(214.3 31.8% 91.4%);
  --input: hsl(214.3 31.8% 91.4%);
  --ring: hsl(221.2 83.2% 53.3%);
  --radius: 0.5rem;
}

.dark {
  --background: hsl(222.2 84% 4.9%);
  --foreground: hsl(210 40% 98%);
  /* ... 深色模式覆盖样式 */
}

NeonAuthUIProvider Props

NeonAuthUIProvider属性

Full configuration options:
typescript
<NeonAuthUIProvider
  // Required
  authClient={authClient}

  // Navigation (Next.js specific)
  navigate={router.push}        // router.push for navigation
  replace={router.replace}      // router.replace for redirects
  onSessionChange={() => router.refresh()} // Refresh Server Components!
  redirectTo="/dashboard"       // Where to redirect after auth
  Link={({href, children}) => <Link to={href}>{children}</Link>}                   // Next.js Link component

  // Social/OAuth Providers
  social={{
    providers: ['google'],
  }}

  // Feature Flags
  emailOTP={true}               // Enable email OTP sign-in
  emailVerification={true}      // Require email verification
  magicLink={false}             // Magic link (disabled by default)
  multiSession={false}          // Multiple sessions (disabled)

  // Credentials Configuration
  credentials={{
    forgotPassword: true,       // Show forgot password link
  }}

  // Sign Up Fields
  signUp={{
    fields: ['name'],           // Additional fields: 'name', 'username', etc.
  }}

  // Account Settings Fields
  account={{
    fields: ['image', 'name', 'company', 'age', 'newsletter'],
  }}

  // Organization Features
  organization={{}}             // Enable org features

  // Dark Mode
  defaultTheme="system"         // 'light' | 'dark' | 'system'

  // Custom Labels
  localization={{
    SIGN_IN: 'Welcome Back',
    SIGN_UP: 'Create Account',
    FORGOT_PASSWORD: 'Forgot Password?',
    OR_CONTINUE_WITH: 'or continue with',
  }}
>
  {children}
</NeonAuthUIProvider>

完整配置选项:
typescript
<NeonAuthUIProvider
  // 必填项
  authClient={authClient}

  // 导航(Next.js专属)
  navigate={router.push}        // 使用router.push进行导航
  replace={router.replace}      // 使用router.replace进行重定向
  onSessionChange={() => router.refresh()} // 刷新服务器组件!
  redirectTo="/dashboard"       // 认证完成后重定向的目标路径
  Link={({href, children}) => <Link to={href}>{children}</Link>}                   // Next.js Link组件

  // 社交/OAuth提供者
  social={{
    providers: ['google'],
  }}

  // 功能开关
  emailOTP={true}               // 启用邮箱OTP登录
  emailVerification={true}      // 要求邮箱验证
  magicLink={false}             // 魔法链接(默认禁用)
  multiSession={false}          // 多会话支持(默认禁用)

  // 凭证配置
  credentials={{
    forgotPassword: true,       // 显示忘记密码链接
  }}

  // 注册字段
  signUp={{
    fields: ['name'],           // 额外字段:'name', 'username'等
  }}

  // 账户设置字段
  account={{
    fields: ['image', 'name', 'company', 'age', 'newsletter'],
  }}

  // 组织功能
  organization={{}}             // 启用组织功能

  // 深色模式
  defaultTheme="system"         // 可选值:'light' | 'dark' | 'system'

  // 自定义标签文本
  localization={{
    SIGN_IN: '欢迎回来',
    SIGN_UP: '创建账户',
    FORGOT_PASSWORD: '忘记密码?',
    OR_CONTINUE_WITH: '或通过以下方式登录',
  }}
>
  {children}
</NeonAuthUIProvider>

Server Components (RSC)

服务器组件(RSC)

Get Session in Server Component

在服务器组件中获取会话

typescript
// NO 'use client' - this is a Server Component
import { auth } from '@/lib/auth/server';

// Server components using `auth` methods must be rendered dynamically
export const dynamic = 'force-dynamic'

export async function Profile() {
  const { data: session } = await auth.getSession();

  if (!session?.user) return <div>Not signed in</div>;

  return (
    <div>
      <p>Hello, {session.user.name}</p>
      <p>Email: {session.user.email}</p>
    </div>
  );
}
typescript
// 无需添加'use client' - 这是一个服务器组件
import { auth } from '@/lib/auth/server';

// 使用`auth`方法的服务器组件必须动态渲染
export const dynamic = 'force-dynamic'

export async function Profile() {
  const { data: session } = await auth.getSession();

  if (!session?.user) return <div>未登录</div>;

  return (
    <div>
      <p>你好,{session.user.name}</p>
      <p>邮箱:{session.user.email}</p>
    </div>
  );
}

Route Handler with Auth

带认证的路由处理器

typescript
// app/api/user/route.ts
import { auth } from '@/lib/auth/server';
import { NextResponse } from 'next/server';

export async function GET() {
  const { data: session } = await auth.getSession();

  if (!session?.user) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  return NextResponse.json({ user: session.user });
}

typescript
// app/api/user/route.ts
import { auth } from '@/lib/auth/server';
import { NextResponse } from 'next/server';

export async function GET() {
  const { data: session } = await auth.getSession();

  if (!session?.user) {
    return NextResponse.json({ error: '未授权' }, { status: 401 });
  }

  return NextResponse.json({ user: session.user });
}

Server Actions

服务器操作

Server actions use the same
auth
instance from
lib/auth/server.ts
:
服务器操作使用
lib/auth/server.ts
中的同一个
auth
实例:

Sign In Action

登录操作

typescript
// app/actions/auth.ts
'use server';
import { auth } from '@/lib/auth/server';
import { redirect } from 'next/navigation';

export async function signIn(formData: FormData) {
  const { error } = await auth.signIn.email({
    email: formData.get('email') as string,
    password: formData.get('password') as string,
  });

  if (error) {
    return { error: error.message };
  }

  redirect('/dashboard');
}

export async function signUp(formData: FormData) {
  const { error } = await auth.signUp.email({
    email: formData.get('email') as string,
    password: formData.get('password') as string,
    name: formData.get('name') as string,
  });

  if (error) {
    return { error: error.message };
  }

  redirect('/dashboard');
}

export async function signOut() {
  await auth.signOut();
  redirect('/');
}
typescript
// app/actions/auth.ts
'use server';
import { auth } from '@/lib/auth/server';
import { redirect } from 'next/navigation';

export async function signIn(formData: FormData) {
  const { error } = await auth.signIn.email({
    email: formData.get('email') as string,
    password: formData.get('password') as string,
  });

  if (error) {
    return { error: error.message };
  }

  redirect('/dashboard');
}

export async function signUp(formData: FormData) {
  const { error } = await auth.signUp.email({
    email: formData.get('email') as string,
    password: formData.get('password') as string,
    name: formData.get('name') as string,
  });

  if (error) {
    return { error: error.message };
  }

  redirect('/dashboard');
}

export async function signOut() {
  await auth.signOut();
  redirect('/');
}

Available Server Methods

可用的服务器端方法

The
auth
instance from
createNeonAuth()
provides all Better Auth server methods:
typescript
// Authentication
auth.signIn.email({ email, password })
auth.signUp.email({ email, password, name })
auth.signOut()
auth.getSession()

// User Management
auth.updateUser({ name, image })

// Organizations
auth.organization.create({ name, slug })
auth.organization.list()

// Admin (if enabled)
auth.admin.listUsers()
auth.admin.banUser({ userId })

createNeonAuth()
返回的
auth
实例提供所有Better Auth服务器端方法:
typescript
// 认证相关
auth.signIn.email({ email, password })
auth.signUp.email({ email, password, name })
auth.signOut()
auth.getSession()

// 用户管理
auth.updateUser({ name, image })

// 组织相关
auth.organization.create({ name, slug })
auth.organization.list()

// 管理员功能(若启用)
auth.admin.listUsers()
auth.admin.banUser({ userId })

Client Components

客户端组件

Session Hook

会话Hook

typescript
'use client';
import { authClient } from '@/lib/auth/client';

export function Dashboard() {
  const { data: session, isPending, error } = authClient.useSession();

  if (isPending) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!session) return <div>Not signed in</div>;

  return <div>Hello, {session.user.name}</div>;
}
typescript
'use client';
import { authClient } from '@/lib/auth/client';

export function Dashboard() {
  const { data: session, isPending, error } = authClient.useSession();

  if (isPending) return <div>加载中...</div>;
  if (error) return <div>错误:{error.message}</div>;
  if (!session) return <div>未登录</div>;

  return <div>你好,{session.user.name}</div>;
}

Client-Side Auth Methods

客户端认证方法

typescript
'use client';
import { authClient } from '@/lib/auth/client';

// Sign in
await authClient.signIn.email({ email, password });

// Sign up
await authClient.signUp.email({ email, password, name });

// OAuth
await authClient.signIn.social({
  provider: 'google',
  callbackURL: '/dashboard',
});

// Sign out
await authClient.signOut();

// Get session
const session = await authClient.getSession();

typescript
'use client';
import { authClient } from '@/lib/auth/client';

// 登录
await authClient.signIn.email({ email, password });

// 注册
await authClient.signUp.email({ email, password, name });

// OAuth登录
await authClient.signIn.social({
  provider: 'google',
  callbackURL: '/dashboard',
});

// 登出
await authClient.signOut();

// 获取会话
const session = await authClient.getSession();

UI Components

UI组件

AuthView - Main Auth Interface

AuthView - 主认证界面

typescript
import { AuthView } from '@neondatabase/auth/react/ui';

// Handles: sign-in, sign-up, forgot-password, reset-password, callback, sign-out
<AuthView pathname={path} />
typescript
import { AuthView } from '@neondatabase/auth/react/ui';

// 处理:登录、注册、忘记密码、重置密码、回调、登出
<AuthView pathname={path} />

Conditional Rendering

条件渲染

typescript
import {
  SignedIn,
  SignedOut,
  AuthLoading,
  RedirectToSignIn,
} from '@neondatabase/auth/react/ui';

function MyPage() {
  return (
    <>
      <AuthLoading>
        <LoadingSpinner />
      </AuthLoading>

      <SignedIn>
        <Dashboard />
      </SignedIn>

      <SignedOut>
        <LandingPage />
      </SignedOut>

      {/* Auto-redirect if not signed in */}
      <RedirectToSignIn />
    </>
  );
}
typescript
import {
  SignedIn,
  SignedOut,
  AuthLoading,
  RedirectToSignIn,
} from '@neondatabase/auth/react/ui';

function MyPage() {
  return (
    <>
      <AuthLoading>
        <LoadingSpinner />
      </AuthLoading>

      <SignedIn>
        <Dashboard />
      </SignedIn>

      <SignedOut>
        <LandingPage />
      </SignedOut>

      {/* 未登录时自动重定向 */}
      <RedirectToSignIn />
    </>
  );
}

UserButton

用户按钮

typescript
import { UserButton } from '@neondatabase/auth/react/ui';

function Header() {
  return (
    <header>
      <nav>...</nav>
      <UserButton />
    </header>
  );
}
typescript
import { UserButton } from '@neondatabase/auth/react/ui';

function Header() {
  return (
    <header>
      <nav>...</nav>
      <UserButton />
    </header>
  );
}

Account Management

账户管理组件

typescript
import {
  AccountSettingsCards,
  SecuritySettingsCards,
  SessionsCard,
  ChangePasswordCard,
  ChangeEmailCard,
  DeleteAccountCard,
  ProvidersCard,
} from '@neondatabase/auth/react/ui';
typescript
import {
  AccountSettingsCards,
  SecuritySettingsCards,
  SessionsCard,
  ChangePasswordCard,
  ChangeEmailCard,
  DeleteAccountCard,
  ProvidersCard,
} from '@neondatabase/auth/react/ui';

Organization Components

组织组件

typescript
import {
  OrganizationSwitcher,
  OrganizationSettingsCards,
  OrganizationMembersCard,
  AcceptInvitationCard,
} from '@neondatabase/auth/react/ui';

typescript
import {
  OrganizationSwitcher,
  OrganizationSettingsCards,
  OrganizationMembersCard,
  AcceptInvitationCard,
} from '@neondatabase/auth/react/ui';

Social/OAuth Providers

社交/OAuth提供者

Configuration

配置

typescript
<NeonAuthUIProvider
  social={{
    providers: ['google'],
  }}
>
typescript
<NeonAuthUIProvider
  social={{
    providers: ['google'],
  }}
>

Programmatic OAuth

程序化OAuth

typescript
// Client-side
await authClient.signIn.social({
  provider: 'google',
  callbackURL: '/dashboard',
});
typescript
// 客户端
await authClient.signIn.social({
  provider: 'google',
  callbackURL: '/dashboard',
});

Supported Providers

支持的提供者

google
,
github
,
twitter
,
discord
,
apple
,
microsoft
,
facebook
,
linkedin
,
spotify
,
twitch
,
gitlab
,
bitbucket

google
,
github
,
twitter
,
discord
,
apple
,
microsoft
,
facebook
,
linkedin
,
spotify
,
twitch
,
gitlab
,
bitbucket

Middleware Configuration

中间件配置

Basic Protected Routes

基础保护路由

typescript
import { auth } from '@/lib/auth/server';

export default auth.middleware({
  loginUrl: '/auth/sign-in',
});

export const config = {
  matcher: ['/dashboard/:path*', '/account/:path*', '/settings/:path*'],
};
typescript
import { auth } from '@/lib/auth/server';

export default auth.middleware({
  loginUrl: '/auth/sign-in',
});

export const config = {
  matcher: ['/dashboard/:path*', '/account/:path*', '/settings/:path*'],
};

Custom Logic

自定义逻辑

typescript
import { auth } from '@/lib/auth/server';
import { NextResponse } from 'next/server';

export default auth.middleware({
  loginUrl: '/auth/sign-in',
});

typescript
import { auth } from '@/lib/auth/server';
import { NextResponse } from 'next/server';

export default auth.middleware({
  loginUrl: '/auth/sign-in',
});

Account Pages Setup

账户页面配置

Account Layout (
app/account/[path]/page.tsx
)

账户布局(
app/account/[path]/page.tsx

typescript
import {
  SignedIn,
  RedirectToSignIn,
  AccountSettingsCards,
  SecuritySettingsCards,
  SessionsCard,
  ChangePasswordCard,
} from '@neondatabase/auth/react/ui';

export default async function AccountPage({ params }: { params: Promise<{ path: string }> }) {
  const { path = 'settings' } = await params;

  return (
    <>
      <RedirectToSignIn />
      <SignedIn>
        {path === 'settings' && <AccountSettingsCards />}
        {path === 'security' && (
          <>
            <ChangePasswordCard />
            <SecuritySettingsCards />
          </>
        )}
        {path === 'sessions' && <SessionsCard />}
      </SignedIn>
    </>
  );
}

typescript
import {
  SignedIn,
  RedirectToSignIn,
  AccountSettingsCards,
  SecuritySettingsCards,
  SessionsCard,
  ChangePasswordCard,
} from '@neondatabase/auth/react/ui';

export default async function AccountPage({ params }: { params: Promise<{ path: string }> }) {
  const { path = 'settings' } = await params;

  return (
    <>
      <RedirectToSignIn />
      <SignedIn>
        {path === 'settings' && <AccountSettingsCards />}
        {path === 'security' && (
          <>
            <ChangePasswordCard />
            <SecuritySettingsCards />
          </>
        )}
        {path === 'sessions' && <SessionsCard />}
      </SignedIn>
    </>
  );
}

Advanced Features

高级功能

Anonymous Access

匿名访问

Enable RLS-based data access for unauthenticated users:
typescript
// lib/auth/client.ts
'use client';
import { createAuthClient } from '@neondatabase/auth/next';

export const authClient = createAuthClient({
  allowAnonymous: true,
});
为未认证用户启用基于RLS的数据访问:
typescript
// lib/auth/client.ts
'use client';
import { createAuthClient } from '@neondatabase/auth/next';

export const authClient = createAuthClient({
  allowAnonymous: true,
});

Get JWT Token

获取JWT令牌

typescript
const token = await authClient.getJWTToken();

// Use in API calls
const response = await fetch('/api/data', {
  headers: { Authorization: `Bearer ${token}` },
});
typescript
const token = await authClient.getJWTToken();

// 在API调用中使用
const response = await fetch('/api/data', {
  headers: { Authorization: `Bearer ${token}` },
});

Cross-Tab Sync

跨标签页同步

Automatic via BroadcastChannel. Sign out in one tab signs out all tabs.
通过BroadcastChannel自动实现。在一个标签页登出会同步所有标签页的登出状态。

Session Refresh in Server Components

服务器组件中的会话刷新

The
onSessionChange
callback is crucial for Next.js:
typescript
<NeonAuthUIProvider
  onSessionChange={() => router.refresh()} // Refreshes Server Components!
  // ...
>
Without this, Server Components won't update after sign-in/sign-out.

onSessionChange
回调对Next.js至关重要:
typescript
<NeonAuthUIProvider
  onSessionChange={() => router.refresh()} // 刷新服务器组件!
  // ...
>
如果没有该回调,服务器组件在登录/登出后不会更新。

Error Handling

错误处理

Server Actions

服务器操作

typescript
'use server';

export async function signIn(formData: FormData) {
  const { error } = await authServer.signIn.email({
    email: formData.get('email') as string,
    password: formData.get('password') as string,
  });

  if (error) {
    // Return error to client
    return { error: error.message };
  }

  redirect('/dashboard');
}
typescript
'use server';

export async function signIn(formData: FormData) {
  const { error } = await authServer.signIn.email({
    email: formData.get('email') as string,
    password: formData.get('password') as string,
  });

  if (error) {
    // 将错误返回给客户端
    return { error: error.message };
  }

  redirect('/dashboard');
}

Client Components

客户端组件

typescript
'use client';

const { error } = await authClient.signIn.email({ email, password });

if (error) {
  toast.error(error.message);
}
typescript
'use client';

const { error } = await authClient.signIn.email({ email, password });

if (error) {
  toast.error(error.message);
}

Common Errors

常见错误

ErrorCause
Invalid credentials
Wrong email/password
User already exists
Email already registered
Email not verified
Verification required
Session not found
Expired or invalid session

错误信息原因
Invalid credentials
邮箱或密码错误
User already exists
该邮箱已注册
Email not verified
需要验证邮箱
Session not found
会话已过期或无效

FAQ / Troubleshooting

FAQ / 故障排除

Server Components not updating after sign-in?

登录后服务器组件未更新?

Make sure you have
onSessionChange={() => router.refresh()}
in your provider:
typescript
<NeonAuthUIProvider
  onSessionChange={() => router.refresh()}
  // ...
>
确保在提供者组件中添加了
onSessionChange={() => router.refresh()}
typescript
<NeonAuthUIProvider
  onSessionChange={() => router.refresh()}
  // ...
>

Anonymous access not working?

匿名访问无法工作?

Grant permissions to the
anonymous
role in your database:
sql
GRANT SELECT ON public.posts TO anonymous;
GRANT SELECT ON public.products TO anonymous;
And configure RLS policies:
sql
CREATE POLICY "Anyone can read published posts"
  ON public.posts FOR SELECT
  USING (published = true);
在数据库中为
anonymous
角色授予权限:
sql
GRANT SELECT ON public.posts TO anonymous;
GRANT SELECT ON public.products TO anonymous;
并配置RLS策略:
sql
CREATE POLICY "任何人都可以查看已发布的文章"
  ON public.posts FOR SELECT
  USING (published = true);

Middleware not protecting routes?

中间件未保护路由?

Check your
matcher
configuration:
typescript
export const config = {
  matcher: [
    '/dashboard/:path*',
    '/account/:path*',
    // Add your protected routes here
  ],
};
检查
matcher
配置:
typescript
export const config = {
  matcher: [
    '/dashboard/:path*',
    '/account/:path*',
    // 在此添加需要保护的路由
  ],
};

OAuth callback errors?

OAuth回调出错?

Ensure your API route is set up correctly at
app/api/auth/[...path]/route.ts
:
typescript
import { auth } from '@/lib/auth/server';
export const { GET, POST } = auth.handler();
确保API路由已在
app/api/auth/[...path]/route.ts
中正确配置:
typescript
import { auth } from '@/lib/auth/server';
export const { GET, POST } = auth.handler();

Session not persisting?

会话未持久化?

  1. Check cookies are enabled
  2. Verify
    NEON_AUTH_BASE_URL
    is correct in
    .env.local
  3. Verify
    NEON_AUTH_COOKIE_SECRET
    is set and at least 32 characters
  4. Make sure you're not in incognito with cookies blocked
  1. 检查Cookie是否已启用
  2. 验证
    .env.local
    中的
    NEON_AUTH_BASE_URL
    是否正确
  3. 验证
    NEON_AUTH_COOKIE_SECRET
    已设置且至少32个字符
  4. 确保未在阻止Cookie的隐身模式下测试

Session data cache not working?

会话数据缓存不工作?

  1. Verify
    NEON_AUTH_COOKIE_SECRET
    is at least 32 characters long
  2. Check
    cookies.secret
    is passed to
    createNeonAuth()
  3. Optionally configure
    cookies.sessionDataTtl
    (default: 300 seconds)

  1. 验证
    NEON_AUTH_COOKIE_SECRET
    至少32个字符
  2. 检查
    cookies.secret
    是否已传递给
    createNeonAuth()
  3. 可选择性配置
    cookies.sessionDataTtl
    (默认值:300秒)

Performance Notes

性能说明

  • Session data caching: JWT-signed
    session_data
    cookie with configurable TTL (default: 5 minutes)
    • Configure via
      cookies.sessionDataTtl
      in seconds
    • Enables sub-millisecond session lookups (<1ms)
    • Automatic fallback to upstream
      /get-session
      on cache miss
  • Request deduplication: Concurrent calls share single network request (10x faster cold starts)
  • Server Components: Use
    auth.getSession()
    for zero-JS session access
  • Cross-tab sync: <50ms via BroadcastChannel
  • Cookie domain: Optional
    cookies.domain
    for cross-subdomain cookie sharing
  • 会话数据缓存:使用JWT签名的
    session_data
    Cookie,可配置过期时间(默认:5分钟)
    • 通过
      cookies.sessionDataTtl
      (秒)配置
    • 实现亚毫秒级的会话查询(<1ms)
    • 缓存失效时自动回退到上游
      /get-session
      接口
  • 请求去重:并发请求共享单个网络请求(冷启动速度提升10倍)
  • 服务器组件:使用
    auth.getSession()
    实现零JS会话访问
  • 跨标签页同步:通过BroadcastChannel实现,延迟<50ms
  • Cookie域名:可选的
    cookies.domain
    用于跨子域名共享Cookie