Next.js SDK (@auris/nextjs)
@auris/nextjs v0.1.0@auris/nextjs ist das empfohlene Paket für Next.js-Anwendungen. Es erweitert @auris/react mit serverseitigen Hilfsprogrammen für Server Components, Route Handlers und Vercel Edge Middleware.
Das Paket stellt drei Einstiegspunkte bereit:
| Einstiegspunkt | Umgebung | Inhalt |
|---|---|---|
@auris/nextjs | Client Components | Re-exportiert alles aus @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/jsUmgebungsvariablen
In der .env.local-Datei setzen. Variablen mit NEXT_PUBLIC_-Präfix sind in Client Components verfügbar.
# Clientseitig (Browser und Server)
NEXT_PUBLIC_AURIS_DOMAIN=https://auth.yourdomain.com
NEXT_PUBLIC_AURIS_CLIENT_ID=app_xxxxx
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Serverseitig: von aurisMiddleware, getSession, withAuth, requirePermission verwendet
AURIS_DOMAIN=https://auth.yourdomain.com
AURIS_CLIENT_ID=app_xxxxx
# Nur serverseitig (niemals dem Browser ausgesetzt)
AURIS_CLIENT_SECRET=cs_live_xxxxx
AURIS_TENANT=my-tenant
# Optional: ermöglicht lokale JWT-Verifizierung ohne Netzwerkaufruf
AURIS_JWKS_URL=https://auth.yourdomain.com/.well-known/jwks.jsonAURIS_CLIENT_SECRET niemals in einer Variable mit NEXT_PUBLIC_-Präfix einschließen. Das Secret muss ausschließlich serverseitig bleiben.
Einrichtung
Paket installieren und Umgebungsvariablen setzen
Die obigen Installations- und Umgebungsvariablen-Schritte befolgen.
AurisProvider zum Root-Layout hinzufügen
Die Anwendung in eine Client-Komponente einbetten, die den Auris-Kontext für alle untergeordneten Client Components bereitstellt.
// 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="de">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}Edge Middleware konfigurieren
Routen schützen, bevor sie deine Anwendungslogik erreichen.
// middleware.ts (im Projektstamm, auf gleicher Ebene wie app/)
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware({
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
protectedPaths: ['/dashboard/*', '/settings/*'],
publicPaths: ['/', '/about', '/pricing', '/auth/*'],
loginUrl: '/auth/login',
})
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico|api/public).*)'],
}Login- und Callback-Seiten erstellen
// 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>Wird zur Anmeldung weitergeleitet...</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 { isAuthenticated, isLoading, error } = useAuris()
const router = useRouter()
useEffect(() => {
// AurisProvider führt den Code-Austausch beim Mount automatisch durch
if (!isLoading && isAuthenticated) router.push('/dashboard')
}, [isLoading, isAuthenticated, router])
if (error) return <p>Anmeldung fehlgeschlagen: {error.message}</p>
return <p>Anmeldung wird abgeschlossen...</p>
}AurisProvider erkennt die Query-Parameter code und state beim Mount und führt den
Token-Austausch selbst durch — die Callback-Seite muss nur auf isAuthenticated warten und
navigieren. Wenn du den Austausch manuell auslösen musst (z. B. außerhalb des Providers),
verwende useAuris().client.handleRedirectCallback().
Middleware (@auris/nextjs/middleware)
aurisMiddleware(config)
Schützt Routen am Edge, bevor sie deine Anwendung erreichen. Validiert das Sitzungs-Cookie des Benutzers und leitet nicht authentifizierte Benutzer zur Login-URL weiter.
Konfiguration:
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
domain | string | erforderlich | Basis-URL der Auris-API |
clientId | string | erforderlich | OAuth-Client-ID |
tenant | string | 'default' | Tenant-/Realm-Name |
protectedPaths | string[] | [] | Pfade, die Authentifizierung erfordern. Exakte Übereinstimmung oder Präfix-Match mit abschließendem /* (z. B. '/dashboard/*') |
publicPaths | string[] | [] | Pfade, die Auth-Prüfungen vollständig umgehen (gleiche Matching-Regeln) |
loginUrl | string | '/login' | Wohin nicht authentifizierte Benutzer umgeleitet werden. Der ursprünglich angeforderte Pfad wird als ?callbackUrl= übergeben |
callbackPaths | string[] | alle geschützten Pfade | Pfade, die den OAuth2-Callback (?code=&state=) ohne Authentifizierung empfangen dürfen |
Pfadmuster sind keine regulären Ausdrücke: Ein Muster passt entweder exakt oder als
Präfix, wenn es auf /* endet ('/dashboard/*' passt auf /dashboard und alles darunter).
// middleware.ts
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware({
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
protectedPaths: [
'/dashboard/*',
'/settings/*',
'/api/protected/*',
],
publicPaths: [
'/',
'/about',
'/pricing',
'/blog/*',
'/auth/*',
'/api/public/*',
],
loginUrl: '/auth/login',
// Den OAuth-Callback (?code=&state=) nur auf diesem Pfad erlauben
callbackPaths: ['/auth/callback'],
})
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}Das Modul exportiert außerdem sanitizeCallbackUrl(url), das einen callbackUrl-Wert auf einen
relativen Same-Origin-Pfad beschränkt. Verwende es auf deiner Login-Seite, bevor du zu dem von
der Middleware geschriebenen Query-Parameter callbackUrl weiterleitest:
import { sanitizeCallbackUrl } from '@auris/nextjs/middleware'
const target = sanitizeCallbackUrl(searchParams.get('callbackUrl') ?? '/')
router.replace(target)Serverseitige Helfer (@auris/nextjs/server)
getSession(config)
Gibt die Sitzung des Benutzers in einem Server Component oder Route Handler zurück. Liest das accessToken-Cookie und validiert es gegen die Auris-API (oder lokal, ohne Netzwerkaufruf, wenn jwksUrl in der Konfiguration oder über die Umgebungsvariable AURIS_JWKS_URL gesetzt ist).
Signatur:
import { getSession } from '@auris/nextjs/server'
const session = await getSession({
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
}) // Promise<AurisSession | null>Rückgabewert:
interface AurisSession {
userId: string
email: string
username?: string
firstName?: string
lastName?: string
roles: string[]
tenant?: string
accessToken: string
}// 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({
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
})
if (!session) redirect('/auth/login')
return (
<div>
<h1>Willkommen, {session.firstName}</h1>
<p>Deine E-Mail: {session.email}</p>
</div>
)
}withAuth(handler, config)
Higher-Order-Funktion, die einen Route Handler umhüllt und die authentifizierte Sitzung als req.session injiziert. Gibt eine 401-Antwort zurück, wenn der Benutzer nicht authentifiziert ist, und eine 403-Antwort, wenn die optionale permission aus der Konfiguration nicht gewährt ist.
Signatur:
import { withAuth } from '@auris/nextjs/server'
export const GET = withAuth(
async (req: AuthenticatedRequest) => Response, // req.session: AurisSession
{
domain: string, // erforderlich
clientId: string, // erforderlich
tenant?: string,
jwksUrl?: string,
permission?: string | string[], // optionale Berechtigungsprüfung (403 bei Fehlschlag)
}
)// app/api/profile/route.ts
import { withAuth } from '@auris/nextjs/server'
const aurisConfig = {
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
}
export const GET = withAuth(async (req) => {
return Response.json({
id: req.session.userId,
email: req.session.email,
roles: req.session.roles,
})
}, aurisConfig)
export const PATCH = withAuth(async (req) => {
const body = await req.json()
const updated = await updateProfile(req.session.userId, body)
return Response.json(updated)
}, aurisConfig)requirePermission(permission, config, handler)
Wie withAuth, erzwingt aber auch eine bestimmte Berechtigung. Gibt eine 403-Antwort zurück, wenn der Benutzer authentifiziert ist, aber die erforderliche Berechtigung fehlt.
Signatur:
import { requirePermission } from '@auris/nextjs/server'
export const DELETE = requirePermission(
'delete:documents', // string | string[]
{ domain: string, clientId: string, tenant?: string },
async (req: AuthenticatedRequest) => Response // req.session: AurisSession
)// app/api/documents/[id]/route.ts
import { requirePermission, withAuth } from '@auris/nextjs/server'
const aurisConfig = {
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
}
export const GET = withAuth(async (req) => {
const id = new URL(req.url).pathname.split('/').at(-1)
const doc = await getDocument(id, req.session.userId)
return Response.json(doc)
}, aurisConfig)
export const DELETE = requirePermission(
'delete:documents',
aurisConfig,
async (req) => {
const id = new URL(req.url).pathname.split('/').at(-1)
await deleteDocument(id, req.session.userId)
return Response.json({ deleted: true })
}
)checkPermission(permission, config)
Gibt einen Boolean zurück, der angibt, ob der aktuelle Benutzer eine bestimmte Berechtigung hat (oder alle übergebenen Berechtigungen, wenn ein Array übergeben wird). Für Server Components mit bedingtem Rendering auf Basis von Berechtigungen.
Signatur:
import { checkPermission } from '@auris/nextjs/server'
const allowed = await checkPermission('manage:users', {
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
}) // Promise<boolean>// app/admin/page.tsx — Server Component
import { getSession, checkPermission } from '@auris/nextjs/server'
import { redirect } from 'next/navigation'
const aurisConfig = {
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
}
export default async function AdminPage() {
const session = await getSession(aurisConfig)
if (!session) redirect('/auth/login')
const canManageUsers = await checkPermission('manage:users', aurisConfig)
const canViewReports = await checkPermission('view:reports', aurisConfig)
return (
<div>
<h1>Admin-Panel</h1>
{canManageUsers && <UserManagement />}
{canViewReports && <ReportsTable />}
{!canManageUsers && !canViewReports && <p>Du hast keinen Admin-Zugriff.</p>}
</div>
)
}createServerManagementClient(config?)
Erstellt einen Management-API-Client mit AURIS_CLIENT_SECRET aus den Umgebungsvariablen. Keine Konfiguration erforderlich, wenn die Umgebungsvariablen gesetzt sind; jedes Feld kann über das optionale Konfigurationsargument überschrieben werden.
Signatur:
import { createServerManagementClient } from '@auris/nextjs/server'
const mgmt = createServerManagementClient()// app/api/admin/users/route.ts
import { createServerManagementClient, requirePermission } from '@auris/nextjs/server'
const aurisConfig = {
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
}
export const GET = requirePermission('manage:users', aurisConfig, async () => {
const mgmt = createServerManagementClient()
const { users } = await mgmt.users.list({ page: 1, limit: 50 })
return Response.json({ users })
})createServerFgaClient()
Erstellt einen FGA-Client mit einem M2M-Access-Token für serverseitige Fine-Grained-Authorization-Checks.
// app/api/documents/[id]/route.ts
import { withAuth, createServerFgaClient } from '@auris/nextjs/server'
export const GET = withAuth(async (req) => {
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: req.session.userId,
})
if (!allowed) {
return Response.json({ error: 'Zugriff verweigert' }, { status: 403 })
}
const doc = await getDocument(docId)
return Response.json(doc)
}, {
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
})Client Components
Alle Hooks und Komponenten aus @auris/react werden von @auris/nextjs re-exportiert. In Client Components aus @auris/nextjs importieren:
// In Next.js Client Components — @auris/nextjs verwenden, nicht @auris/react
'use client'
import { useAuris, useUser, usePermissions, AuthGuard, PermissionGate } from '@auris/nextjs'Vollständige Referenz aller Hooks und Komponenten auf der React-SDK-Seite.
Vollständiges Anwendungsbeispiel
// 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>
)
}// middleware.ts
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware({
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
protectedPaths: ['/dashboard/*'],
publicPaths: ['/', '/auth/*'],
loginUrl: '/auth/login',
})
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}// app/dashboard/page.tsx — Server Component
import { getSession, checkPermission } from '@auris/nextjs/server'
import { redirect } from 'next/navigation'
const aurisConfig = {
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
}
export default async function DashboardPage() {
const session = await getSession(aurisConfig)
if (!session) redirect('/auth/login')
const isAdmin = await checkPermission('manage:users', aurisConfig)
return (
<main>
<h1>Willkommen, {session.firstName}</h1>
{isAdmin && (
<a href="/dashboard/admin">Zum Admin-Panel</a>
)}
</main>
)
}// app/api/admin/users/route.ts
import { requirePermission, createServerManagementClient } from '@auris/nextjs/server'
const aurisConfig = {
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
}
export const GET = requirePermission('manage:users', aurisConfig, async () => {
const mgmt = createServerManagementClient()
const result = await mgmt.users.list({ page: 1, limit: 50 })
return Response.json(result)
})Verwandte Seiten
- React SDK — Von @auris/nextjs re-exportierte Hooks und Komponenten
- JavaScript SDK — Low-Level-SDK, das React und Next.js zugrunde liegt
- Hosted Login Guide — PKCE-Flow im Detail
- Berechtigungen — RBAC-Referenz
- FGA Guide — Fine-Grained Authorization