Next.js (App Router)
Integrate Aura Auth and Next.js App Router
This guide walks you through creating a complete authentication flow using Aura Auth directly with the Next.js App Router's native Route Handlers and Server Actions.
Overview
Aura Auth and Next.js App Router both follow the web-standard Request and Response interfaces for high-performance HTTP handling. That makes the integration straightforward: you can mount Aura Auth directly in Route Handlers and use the same api object in Server Components and Server Actions.
Before continuing, complete the installation and initial setup:
- Quick Start Guide to create your Aura Auth instance
- TypeScript Configuration for TypeScript-specific setup
- Next.js Installation Guide to set up your Next.js project
Then use this guide to integrate Aura Auth with a Next.js application using best practices.
What You'll Build
You will create a small Next.js App Router setup with:
- a shared
src/lib/auth.tsserver configuration - an
app/api/auth/[...aura]/route.tshandler - an optional
src/lib/auth-client.tsbrowser client - server and client examples for sign-in, session lookup, and sign-out
Project Structure
Environment Setup
Create a .env.local file at the root of your project to store secrets securely.
# 32-bytes (256-bit) secret used to sign/encrypt sessions. Use a secure random value.
AURA_AUTH_SECRET="base64-or-hex-32-bytes"
AURA_AUTH_SALT="base64-or-hex-32-bytes".env.local file to version control. Use a secret manager in production.Setup Aura Auth
HTTP Handlers
Create an auth.ts file in src/lib/ to configure authentication and export the helpers used by both route handlers and server utilities.
import { createAuth } from "@aura-stack/auth"
export const auth = createAuth({
oauth: ["github"],
basePath: "/api/auth",
baseURL: "http://localhost:3000",
})
export const { handlers, jose, api } = authbasePath must match the route mounted in app/api/auth/[...aura]/route.ts. baseURL should point to your local development server or deployed application URL.
Client API
To use Aura Auth's client-side features, create an auth-client.ts file to initialize the client.
import { createAuthClient } from "@aura-stack/auth/client"
export const authClient = createAuthClient({
basePath: "/api/auth",
baseURL: "http://localhost:3000",
})The baseURL should point to your server's URL, and basePath MUST match the path where your auth routes are mounted.
Mount HTTP Handlers
Create a catch-all route to handle all authentication endpoints dynamically. Next.js App Router uses standard Web Request and Response objects, so the route can forward requests directly to Aura Auth handlers.
import { handlers } from "@/lib/auth"
export const { GET, POST, PATCH } = handlersThis route handles all requests under /api/auth/*.
Usage
Server Side Rendering (SSR)
The api object is designed for server environments such as Server Components and Server Actions.
When you need the active session on the server, pass the current request headers using headers() from next/headers. That gives Aura Auth access to the cookies and headers required to identify the session.
Sign-In
import { api } from "@/lib/auth"
import { redirect } from "next/navigation"
export default function LoginPage() {
const signInAction = async () => {
"use server"
const signIn = await api.signIn("github", {
redirect: false,
redirectTo: "/dashboard",
})
redirect(signIn.signInURL)
}
return (
<form action={signInAction}>
<button type="submit">Sign in with GitHub</button>
</form>
)
}Use this pattern when you want the server action to own the redirect destination while Aura Auth handles the provider flow.
Get Session
import { api } from "@/lib/auth"
import { headers } from "next/headers"
import { redirect } from "next/navigation"
export default async function DashboardPage() {
const headersStore = await headers()
const { session, authenticated } = await api.getSession({ headers: headersStore })
if (!authenticated) {
redirect("/login")
}
return (
<div>
<h1>Welcome back, {session.user?.name}</h1>
<img src={session.user?.image} alt="Profile Avatar" />
</div>
)
}This is the recommended pattern for protected App Router pages: check the session before rendering any private UI.
Sign Out
import { api } from "@/lib/auth"
import { headers } from "next/headers"
import { redirect } from "next/navigation"
export default async function DashboardPage() {
const signOutAction = async () => {
"use server"
const headerStore = await headers()
const response = await api.signOut({
headers: headerStore,
})
if (response.ok) {
redirect("/home")
}
}
return (
<form action={signOutAction}>
<button type="submit">Sign Out</button>
</form>
)
}If you prefer a client-only interaction, you can call authClient.signOut() from a client component instead.
Client Side Rendering (CSR)
Sign In
"use client"
import { authClient } from "@/lib/auth-client"
export const SignInButton = () => {
const handleSignIn = async () => {
await authClient.signIn("github", {
redirectTo: "/dashboard",
})
}
return <button onClick={handleSignIn}>Sign in with GitHub</button>
}Use a client component when you need a clickable auth button, custom modal, or other interactive sign-in entry point.
Get Session
"use client"
import { useEffect, useState } from "react"
import { authClient } from "@/lib/auth-client"
export const UserProfile = () => {
const [session, setSession] = useState(null)
useEffect(() => {
const fetchSession = async () => {
const { session } = await authClient.getSession()
setSession(session)
}
fetchSession()
}, [])
if (!session) return <div>Loading...</div>
return (
<div>
<h1>Welcome back, {session.user?.name}</h1>
<img src={session.user?.image} alt="Profile Avatar" />
</div>
)
}This is useful for session-aware UI that updates after hydration or after a client-side navigation.
Sign Out
To easily check sessions or log out from client components, use createAuthClient.
"use client"
import { authClient } from "@/lib/auth-client"
export const SignOutButton = () => {
const handleSignOut = async () => {
await authClient.signOut({
redirectTo: "/login",
})
}
return <button onClick={handleSignOut}>Sign out</button>
}Client-side sign-out is a better fit for navigation menus, profile popovers, and other interactive UI.
Common Pitfalls
- Mismatched Paths: Ensure the
basePathin your auth configuration matches the path where your route handlers are mounted. For example, if your handlers are inapp/api/auth/[...aura]/route.ts, thenbasePathshould be/api/auth. - Incorrect Headers: When calling
api.getSessionorapi.signOutfrom server components or actions, always pass the current request headers using Next.js'sheaders()function. This allows Aura Auth to read cookies and manage sessions correctly. - Don't update cookies in signOut: When signing out is called, Aura Auth will return a response with
Set-Cookieheaders and it's required to set the cookies usingcookiesfunction.