Reference documentation for the Neon Auth Next.js server SDK (@neondatabase/auth/next/server). This package provides server-side authentication for Next.js applications using React Server Components, API routes, middleware, and server actions.
For client-side authentication, see the Client SDK reference. For UI components, see the UI Components reference.
Installation
Install the Neon Auth package in your Next.js project using npm, yarn, pnpm, or bun.
npm install @neondatabase/auth@latestEnvironment variables
Configure these environment variables in your
.env.localfile:- NEON_AUTH_BASE_URL (required): Your Neon Auth server URL from the Neon Console
- NEON_AUTH_COOKIE_SECRET (required): Secret for signing session cookies (must be 32+ characters for HMAC-SHA256 security)
Generate a secure secret with:
openssl rand -base64 32# Required: Your Neon Auth server URL NEON_AUTH_BASE_URL=https://your-neon-auth-url.neon.tech # Required: Cookie secret for session data signing (32+ characters) NEON_AUTH_COOKIE_SECRET=your-secret-at-least-32-characters-longcreateNeonAuth()
createNeonAuth(config)Creates a unified auth instance that provides all server-side authentication functionality.
Returns an
authobject with:handler()- Creates API route handlersmiddleware()- Creates Next.js middleware for route protectiongetSession()- Retrieves current session- All Better Auth server methods (signIn, signUp, signOut, etc.)
Parameters
Parameter Type Required Default baseUrl string ✓ - cookies.secret string ✓ - cookies.sessionDataTtl number 300 cookies.domain string - cookies.sameSite string strictlogLevel string warnlogger object console(per level)See Server logging and Upstream fetch errors.
// lib/auth/server.ts 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!, }, // logLevel: 'silent', });Server logging
Neon Auth emits structured logs from the API proxy, middleware, and Better Auth server
fetchfor upstream failures and session issues.Defaults:
logLevel: 'warn'writeserrorandwarntoconsole. SetlogLevel: 'silent'to disable all Neon Authconsoleoutput ('silent'ignores any customlogger). Useinfoordebugfor more detail during local troubleshooting.Custom sink: Pass a partial
loggerobject witherror,warn,info, and/ordebugmethods. Omitted methods still useconsole. Metadata may includeerranddetailfor observability tools.auth.middleware()inherits the same resolved logging configuration fromcreateNeonAuth(no per-request reconfiguration).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! }, logLevel: 'debug', logger: { warn(message, meta) { myLogger.warn({ message, ...meta }); }, }, });logLevel Console output silentNone errorerroronlywarn(default)error,warninfoerror,warn,infodebugall levels auth.handler()
auth.handler()Creates GET and POST route handlers for the Neon Auth API proxy.
Create a catch-all route at
app/api/auth/[...path]/route.ts. This handles all authentication API calls from your client, including:- Sign in/sign up requests
- OAuth callbacks
- Session management
- Email verification
- Password reset
Returns
Object with
GETandPOSTNext.js route handlers.// app/api/auth/[...path]/route.ts import { auth } from '@/lib/auth/server'; export const { GET, POST } = auth.handler();auth.middleware()
auth.middleware(options)Creates Next.js middleware for session validation and route protection.
The middleware automatically:
- Validates session cookies on each request
- Provides session data to server components
- Redirects unauthenticated users to the login page
- Refreshes session tokens when needed
Parameters
View parameters
Parameter Type Required Default loginUrl string /auth/sign-inNext.js version compatibility
proxy.tsreplacesmiddleware.tsin Next.js 16. On earlier versions, name the filemiddleware.tsand exportdefault function middlewareinstead ofproxy. The auth logic is identical.proxy.tsimport { auth } from '@/lib/auth/server'; export default auth.middleware({ loginUrl: '/auth/sign-in' }); export const config = { matcher: [ // Match all paths except static files "/((?!_next/static|_next/image|favicon.ico).*)", ], };auth.getSession()
auth.getSession()Retrieves the current session in Server Components, Server Actions, and API Routes.
- Returns cached session if available (fast)
- Automatically refreshes expired tokens
- Returns null if no active session
Server Components that use
auth.getSession()must exportdynamic = 'force-dynamic'because session data depends on cookies.Returns
Field Type Description dataSession | null Session with user data, or null if not authenticated errorError | null Error object if session retrieval failed // app/dashboard/page.tsx import { auth } from '@/lib/auth/server'; export const dynamic = 'force-dynamic'; export default async function DashboardPage() { const { data: session } = await auth.getSession(); if (!session?.user) { return <div>Not authenticated</div>; } return <h1>Welcome, {session.user.name}</h1>; }auth.signIn.email()
auth.signIn.email(credentials)'use server'; import { auth } from '@/lib/auth/server'; import { redirect } from 'next/navigation'; export async function signIn(formData: FormData) { const { data, 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'); }auth.signIn.social()
auth.signIn.social(options)auth.signIn.emailOtp()
auth.signIn.emailOtp(credentials)auth.signUp.email()
auth.signUp.email(credentials)auth.signOut()
auth.signOut()Sign out the current user. Clears session and authentication tokens.
'use server'; import { auth } from '@/lib/auth/server'; import { redirect } from 'next/navigation'; export async function signOut() { await auth.signOut(); redirect('/auth/sign-in'); }auth.updateUser()
auth.updateUser(data)auth.changePassword()
auth.changePassword(passwords)auth.sendVerificationEmail()
auth.sendVerificationEmail(options)auth.deleteUser()
auth.deleteUser()Delete the current user account. This action is irreversible.
const { data, error } = await auth.deleteUser();auth.emailOtp.sendVerificationOtp()
auth.emailOtp.sendVerificationOtp(options)auth.emailOtp.verifyEmail()
auth.emailOtp.verifyEmail(credentials)auth.listSessions()
auth.listSessions()List all active sessions for the current user.
const { data, error } = await auth.listSessions();auth.revokeSession()
auth.revokeSession(options)auth.revokeOtherSessions()
auth.revokeOtherSessions()Revoke all sessions except the current one.
const { data, error } = await auth.revokeOtherSessions();auth.organization.create()
auth.organization.create(data)auth.organization.list()
auth.organization.list()List the current user's organizations.
const { data, error } = await auth.organization.list();auth.organization.inviteMember()
auth.organization.inviteMember(options)auth.admin.listUsers()
auth.admin.listUsers(options)auth.admin.banUser()
auth.admin.banUser(options)auth.admin.setRole()
auth.admin.setRole(options)Upstream fetch errors
When the SDK cannot reach your Neon Auth server (wrong
baseUrl, DNS, TLS, timeout), the API proxy returns a synthetic 502 JSON body with a stablecode. Server methods such asauth.signIn.email()surface the same codes onerror.codewhen the failure is transport-related.Code Typical cause NETWORK_DNSHostname does not resolve NETWORK_REFUSEDConnection refused NETWORK_TIMEOUTRequest timed out NETWORK_TLSTLS / certificate error NETWORK_RESETConnection reset NETWORK_ABORTRequest aborted NETWORK_ERROROther transport failure Client-visible messages are generic (for example, “Could not resolve authentication server hostname”). Check server logs (set
logLevel: 'debug') fordetailand the raw error.Non-transport failures (unexpected exceptions while handling a response) are re-thrown so Next.js error boundaries still receive the original error. HTTP 4xx upstream responses are logged at
info; 5xx atwarn.'use server'; import { auth } from '@/lib/auth/server'; 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?.code === 'NETWORK_DNS') { return { error: 'Check NEON_AUTH_BASE_URL in .env.local' }; } if (error) { return { error: error.message }; } }Performance features
Session caching
Session data is automatically cached in a signed, HTTP-only cookie to reduce API calls to the Auth Server by 95-99%.
- Default cache TTL: 5 minutes (300 seconds)
- Configurable via
cookies.sessionDataTtl - Automatic expiration based on JWT
expclaim - Synchronous cache clearing on sign-out
- Secure HMAC-SHA256 signing
Request deduplication
Multiple concurrent
getSession()calls are automatically deduplicated:- Single network request for concurrent calls
- 10x faster cold starts
- Reduces server load
// First call: Fetches from Auth Server const { data: session } = await auth.getSession(); // Subsequent calls within TTL: Uses cached data (no API call) const { data: session2 } = await auth.getSession();Configuration reference
Complete configuration options for
createNeonAuth():Option Type Required Default baseUrlstring Yes - cookies.secretstring Yes - cookies.sessionDataTtlnumber No 300 cookies.domainstring No undefined cookies.sameSitestring No strictlogLevelstring No warnloggerobject No console- baseUrl: Your Neon Auth server URL from the Neon Console
- cookies.secret: Secret for HMAC-SHA256 signing (32+ characters)
- cookies.sessionDataTtl: Cache TTL in seconds for the signed
session_datacookie - cookies.domain: For cross-subdomain sessions (for example, ".example.com")
- cookies.sameSite:
strict(default),lax, ornone. Uselaxornoneif you embed the app in a third-party iframe or need cookies on cross-site navigations - logLevel:
silent,error,warn,info, ordebug— see Server logging - logger: Optional custom logger; see Server logging
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!, }, });Project structure
Recommended file structure for Next.js with Neon Auth:
app/api/auth/[...path]/route.ts- Auth API handlersapp/auth/[path]/page.tsx- Auth views (sign-in, sign-up)app/dashboard/page.tsx- Protected pageslib/auth/server.ts- Server auth instancelib/auth/client.ts- Client auth instanceproxy.ts(Next.js 16+) ormiddleware.ts(earlier versions) - Route protection
Next.js version compatibility
proxy.tsreplacesmiddleware.tsin Next.js 16. On earlier versions, name the filemiddleware.tsand exportdefault function middlewareinstead ofproxy. The auth logic is identical.app/ ├── api/ │ └── auth/ │ └── [...path]/ │ └── route.ts ├── auth/ │ └── [path]/ │ └── page.tsx ├── dashboard/ │ └── page.tsx ├── actions.ts └── layout.tsx lib/ └── auth/ ├── server.ts └── client.ts proxy.ts # or middleware.ts on Next.js < 16 .env.local
Migration from v0.1
If you're upgrading from Neon Auth SDK v0.1, see the migration guide for step-by-step instructions.
Related documentation
- Client SDK Reference - Client-side authentication
- UI Components Reference - Pre-built auth UI
- Next.js quick start - Getting started guide
- Migration Guide - Upgrading from v0.1
Need help?
Join our Discord Server to ask questions or see what others are doing with Neon. For paid plan support options, see Support.








