Next.js SDK (@auris/nextjs)
@auris/nextjs v0.1.0@auris/nextjs is the recommended package for Next.js applications. It extends @auris/react with server-side utilities that work in Server Components, Route Handlers, and Vercel Edge Middleware.
The package exposes three entry points:
| Entry point | Environment | Contents |
|---|---|---|
@auris/nextjs | Client Components | Re-exports all of @auris/react |
@auris/nextjs/server | Server Components, Route Handlers | getSession, withAuth, requirePermission, checkPermission, createServerManagementClient, createServerFgaClient |
@auris/nextjs/middleware | Edge Middleware | aurisMiddleware |
Installation
npm install @auris/nextjs @auris/react @auris/jsEnvironment Variables
Set these in your .env.local file. Variables prefixed with NEXT_PUBLIC_ are available in Client Components.
# Client-side (both browser and server)
NEXT_PUBLIC_AURIS_DOMAIN=auth.yourdomain.com
NEXT_PUBLIC_AURIS_CLIENT_ID=app_xxxxx
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Server-side only (never exposed to the browser)
AURIS_CLIENT_SECRET=cs_live_xxxxx
AURIS_TENANT=my-tenant
# Optional: enables local JWT verification without a network call
AURIS_JWKS_URL=https://auth.yourdomain.com/.well-known/jwks.jsonNever include AURIS_CLIENT_SECRET in a variable prefixed with NEXT_PUBLIC_. The secret must remain server-side only.
Setup
Install the package and set environment variables
Follow the installation and environment variable steps above.
Add AurisProvider to your root layout
Wrap your application in a Client Component that provides Auris context to all child Client Components.
// app/providers.tsx
'use client'
import { AurisProvider } from '@auris/nextjs'
export function Providers({ children }: { children: React.ReactNode }) {
return (
<AurisProvider
domain={process.env.NEXT_PUBLIC_AURIS_DOMAIN!}
clientId={process.env.NEXT_PUBLIC_AURIS_CLIENT_ID!}
redirectUri={`${process.env.NEXT_PUBLIC_APP_URL}/auth/callback`}
>
{children}
</AurisProvider>
)
}// app/layout.tsx
import { Providers } from './providers'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}Configure Edge Middleware
Protect routes before they reach your application logic.
// middleware.ts (at the project root, same level as app/)
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware({
protectedPaths: ['/dashboard(.*)', '/settings(.*)'],
publicPaths: ['/', '/about', '/pricing', '/auth/(.*)'],
loginUrl: '/auth/login',
})
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico|api/public).*)'],
}Create the login and callback pages
// app/auth/login/page.tsx
'use client'
import { useAuris } from '@auris/nextjs'
import { useEffect } from 'react'
export default function LoginPage() {
const { loginWithRedirect } = useAuris()
useEffect(() => { loginWithRedirect() }, [])
return <p>Redirecting to sign in...</p>
}// app/auth/callback/page.tsx
'use client'
import { useAuris } from '@auris/nextjs'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
export default function CallbackPage() {
const { handleRedirectCallback } = useAuris()
const router = useRouter()
useEffect(() => {
handleRedirectCallback().then(() => router.push('/dashboard'))
}, [])
return <p>Completing sign in...</p>
}Middleware (@auris/nextjs/middleware)
aurisMiddleware(config)
Protects routes at the Edge before they reach your application. Validates the user’s session cookie, and redirects unauthenticated users to the login URL.
Signature:
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware(config: AurisMiddlewareConfig)Configuration:
| Option | Type | Default | Description |
|---|---|---|---|
protectedPaths | string[] | [] | Path patterns (regex-compatible) that require authentication |
publicPaths | string[] | [] | Path patterns that are always accessible without authentication |
loginUrl | string | '/login' | URL to redirect unauthenticated users to |
callbackPath | string | '/auth/callback' | OAuth2 callback path — excluded from protection automatically |
onUnauthorized | (req) => Response | — | Custom handler for unauthenticated requests |
// middleware.ts
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware({
protectedPaths: [
'/dashboard(.*)',
'/settings(.*)',
'/api/protected(.*)',
],
publicPaths: [
'/',
'/about',
'/pricing',
'/blog(.*)',
'/auth/(.*)',
'/api/public(.*)',
],
loginUrl: '/auth/login',
// Custom response for API routes (return 401 instead of redirect)
onUnauthorized: (req) => {
if (req.nextUrl.pathname.startsWith('/api/')) {
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
headers: { 'Content-Type': 'application/json' },
})
}
},
})
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}Server Helpers (@auris/nextjs/server)
getSession()
Returns the user’s session in a Server Component or Route Handler. Reads the session cookie set by the SDK and validates it against the Auris API (or locally if AURIS_JWKS_URL is set).
Signature:
import { getSession } from '@auris/nextjs/server'
const session = await getSession(): Promise<Session | null>Returns:
interface Session {
user: UserInfo
accessToken: string
expiresAt: number // Unix timestamp
}// app/dashboard/page.tsx — Server Component
import { getSession } from '@auris/nextjs/server'
import { redirect } from 'next/navigation'
export default async function DashboardPage() {
const session = await getSession()
if (!session) redirect('/auth/login')
return (
<div>
<h1>Welcome, {session.user.firstName}</h1>
<p>Your email: {session.user.email}</p>
<pre>{JSON.stringify(session.user.roles, null, 2)}</pre>
</div>
)
}withAuth(config, handler)
Higher-order function that wraps a Route Handler and injects the authenticated session. Returns a 401 response if the user is not authenticated.
Signature:
import { withAuth } from '@auris/nextjs/server'
export const GET = withAuth(
{ permission?: string },
async (req: Request, context: { session: Session }) => Response
)// app/api/profile/route.ts
import { withAuth } from '@auris/nextjs/server'
export const GET = withAuth({}, async (req, { session }) => {
return Response.json({
id: session.user.id,
email: session.user.email,
roles: session.user.roles,
})
})
export const PATCH = withAuth({}, async (req, { session }) => {
const body = await req.json()
const updated = await updateProfile(session.user.id, body)
return Response.json(updated)
})requirePermission(permission, config, handler)
Like withAuth, but also enforces a specific permission. Returns a 403 response if the user is authenticated but lacks the required permission.
Signature:
import { requirePermission } from '@auris/nextjs/server'
export const DELETE = requirePermission(
'delete:documents',
{},
async (req: Request, context: { session: Session }) => Response
)// app/api/documents/[id]/route.ts
import { requirePermission, withAuth } from '@auris/nextjs/server'
export const GET = withAuth({}, async (req, { session }) => {
const id = new URL(req.url).pathname.split('/').at(-1)
const doc = await getDocument(id, session.user.id)
return Response.json(doc)
})
export const DELETE = requirePermission(
'delete:documents',
{},
async (req, { session }) => {
const id = new URL(req.url).pathname.split('/').at(-1)
await deleteDocument(id, session.user.id)
return Response.json({ deleted: true })
}
)checkPermission(permission)
Returns a boolean indicating whether the current user has a specific permission. Designed for Server Components where you need conditional rendering based on permissions.
Signature:
import { checkPermission } from '@auris/nextjs/server'
const allowed = await checkPermission('manage:users'): Promise<boolean>// app/admin/page.tsx — Server Component
import { getSession } from '@auris/nextjs/server'
import { checkPermission } from '@auris/nextjs/server'
import { redirect } from 'next/navigation'
export default async function AdminPage() {
const session = await getSession()
if (!session) redirect('/auth/login')
const canManageUsers = await checkPermission('manage:users')
const canViewReports = await checkPermission('view:reports')
return (
<div>
<h1>Admin Panel</h1>
{canManageUsers && <UserManagement />}
{canViewReports && <ReportsTable />}
{!canManageUsers && !canViewReports && <p>You do not have admin access.</p>}
</div>
)
}createServerManagementClient()
Creates a Management API client using AURIS_CLIENT_SECRET from environment variables. No configuration required if the environment variables are set.
Signature:
import { createServerManagementClient } from '@auris/nextjs/server'
const mgmt = await createServerManagementClient()The client authenticates with the OAuth2 client_credentials grant using:
NEXT_PUBLIC_AURIS_DOMAINNEXT_PUBLIC_AURIS_CLIENT_IDAURIS_CLIENT_SECRETAURIS_TENANT
// app/api/admin/users/route.ts
import { createServerManagementClient } from '@auris/nextjs/server'
import { requirePermission } from '@auris/nextjs/server'
export const GET = requirePermission('manage:users', {}, async () => {
const mgmt = await createServerManagementClient()
const { users } = await mgmt.users.list({ page: 1, limit: 50 })
return Response.json({ users })
})createServerFgaClient()
Creates an FGA client with an M2M access token. Use it in Server Components and Route Handlers to perform Fine-Grained Authorization checks server-side.
Signature:
import { createServerFgaClient } from '@auris/nextjs/server'
const fga = await createServerFgaClient()// app/api/documents/[id]/route.ts
import { withAuth } from '@auris/nextjs/server'
import { createServerFgaClient } from '@auris/nextjs/server'
export const GET = withAuth({}, async (req, { session }) => {
const docId = new URL(req.url).pathname.split('/').at(-1)
const fga = await createServerFgaClient()
const { allowed } = await fga.check({
objectType: 'document',
objectId: docId,
relation: 'viewer',
subjectType: 'user',
subjectId: session.user.id,
})
if (!allowed) {
return Response.json({ error: 'Access denied' }, { status: 403 })
}
const doc = await getDocument(docId)
return Response.json(doc)
})Client Components
All hooks and components from @auris/react are re-exported from @auris/nextjs. In Client Components, import from @auris/nextjs instead of @auris/react:
// In Next.js Client Components — use @auris/nextjs, not @auris/react
'use client'
import { useAuris, useUser, usePermissions, AuthGuard, PermissionGate } from '@auris/nextjs'See the React SDK page for the full reference of all hooks and components.
Complete Application Example
A minimal but complete Next.js application with authentication:
app/
layout.tsx — Root layout with AurisProvider
page.tsx — Public home page
providers.tsx — Client component wrapper
auth/
login/page.tsx — Initiates login redirect
callback/page.tsx — Handles redirect from Auris
dashboard/
page.tsx — Protected Server Component
settings/page.tsx — Protected with permission check
api/
profile/route.ts — Protected API route
admin/
users/route.ts — Permission-protected API route
middleware.ts — Edge protection// app/providers.tsx
'use client'
import { AurisProvider } from '@auris/nextjs'
export function Providers({ children }: { children: React.ReactNode }) {
return (
<AurisProvider
domain={process.env.NEXT_PUBLIC_AURIS_DOMAIN!}
clientId={process.env.NEXT_PUBLIC_AURIS_CLIENT_ID!}
redirectUri={`${process.env.NEXT_PUBLIC_APP_URL}/auth/callback`}
>
{children}
</AurisProvider>
)
}// app/layout.tsx
import { Providers } from './providers'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}// middleware.ts
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware({
protectedPaths: ['/dashboard(.*)'],
publicPaths: ['/', '/auth/(.*)'],
loginUrl: '/auth/login',
})
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}// app/auth/login/page.tsx
'use client'
import { useAuris } from '@auris/nextjs'
import { useEffect } from 'react'
export default function LoginPage() {
const { loginWithRedirect } = useAuris()
useEffect(() => { loginWithRedirect() }, [])
return <p>Redirecting to sign in...</p>
}// app/auth/callback/page.tsx
'use client'
import { useAuris } from '@auris/nextjs'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
export default function CallbackPage() {
const { handleRedirectCallback } = useAuris()
const router = useRouter()
useEffect(() => {
handleRedirectCallback().then(() => router.push('/dashboard'))
}, [])
return <p>Completing sign in...</p>
}// app/dashboard/page.tsx — Server Component
import { getSession } from '@auris/nextjs/server'
import { checkPermission } from '@auris/nextjs/server'
import { redirect } from 'next/navigation'
export default async function DashboardPage() {
const session = await getSession()
if (!session) redirect('/auth/login')
const isAdmin = await checkPermission('manage:users')
return (
<main>
<h1>Welcome, {session.user.firstName}</h1>
{isAdmin && (
<a href="/dashboard/admin">Go to Admin Panel</a>
)}
</main>
)
}// app/api/profile/route.ts
import { withAuth } from '@auris/nextjs/server'
export const GET = withAuth({}, async (req, { session }) => {
return Response.json({
id: session.user.id,
email: session.user.email,
name: session.user.name,
roles: session.user.roles,
})
})
export const PATCH = withAuth({}, async (req, { session }) => {
const body = await req.json()
const updated = await updateProfile(session.user.id, body)
return Response.json(updated)
})// app/api/admin/users/route.ts
import { requirePermission, createServerManagementClient } from '@auris/nextjs/server'
export const GET = requirePermission('manage:users', {}, async () => {
const mgmt = await createServerManagementClient()
const result = await mgmt.users.list({ page: 1, limit: 50 })
return Response.json(result)
})Related Pages
- React SDK — Hooks and components re-exported by @auris/nextjs
- JavaScript SDK — Low-level SDK underlying the React and Next.js packages
- Hosted Login Guide — PKCE flow details
- Permissions Guide — RBAC reference
- FGA Guide — Fine-Grained Authorization