SDK Next.js (@auris/nextjs)
@auris/nextjs v0.1.0@auris/nextjs è il pacchetto consigliato per le applicazioni Next.js. Estende @auris/react con utilità server-side che funzionano nei Server Components, Route Handlers e Vercel Edge Middleware.
Il pacchetto espone tre entry point:
| Entry point | Ambiente | Contenuto |
|---|---|---|
@auris/nextjs | Client Components | Ri-esporta tutto @auris/react |
@auris/nextjs/server | Server Components, Route Handlers | getSession, withAuth, requirePermission, checkPermission, createServerManagementClient, createServerFgaClient |
@auris/nextjs/middleware | Edge Middleware | aurisMiddleware |
Installazione
npm install @auris/nextjs @auris/react @auris/jsVariabili d’Ambiente
Impostale nel file .env.local. Le variabili con prefisso NEXT_PUBLIC_ sono disponibili nei Client Components.
# Lato client (sia browser che server)
NEXT_PUBLIC_AURIS_DOMAIN=https://auth.tuodominio.com
NEXT_PUBLIC_AURIS_CLIENT_ID=app_xxxxx
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Lato server: usate da aurisMiddleware, getSession, withAuth, requirePermission
AURIS_DOMAIN=https://auth.tuodominio.com
AURIS_CLIENT_ID=app_xxxxx
# Solo lato server (mai esposto al browser)
AURIS_CLIENT_SECRET=cs_live_xxxxx
AURIS_TENANT=my-tenant
# Opzionale: abilita la verifica JWT locale senza chiamate di rete
AURIS_JWKS_URL=https://auth.tuodominio.com/.well-known/jwks.jsonNon includere mai AURIS_CLIENT_SECRET in una variabile con prefisso NEXT_PUBLIC_. Il segreto deve rimanere solo lato server.
Configurazione
Installa il pacchetto e imposta le variabili d’ambiente
Segui i passaggi di installazione e variabili d’ambiente sopra.
Aggiungi AurisProvider al layout root
Avvolgi la tua applicazione in un Client Component che fornisce il contesto Auris a tutti i Client Components figli.
// 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="it">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}Configura l’Edge Middleware
Proteggi le route prima che raggiungano la logica dell’applicazione.
// middleware.ts (alla radice del progetto, stesso livello di app/)
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware({
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
protectedPaths: ['/dashboard/*', '/impostazioni/*'],
publicPaths: ['/', '/about', '/prezzi', '/auth/*'],
loginUrl: '/auth/login',
})
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico|api/public).*)'],
}Crea le pagine di login e callback
// 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>Reindirizzamento all'accesso in corso...</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 completa lo scambio del codice automaticamente al mount
if (!isLoading && isAuthenticated) router.push('/dashboard')
}, [isLoading, isAuthenticated, router])
if (error) return <p>Accesso non riuscito: {error.message}</p>
return <p>Completamento accesso in corso...</p>
}AurisProvider rileva i parametri query code e state al mount ed esegue da solo lo
scambio del token — la pagina di callback deve solo attendere isAuthenticated e navigare.
Se devi attivare lo scambio manualmente (es. fuori dal provider), usa
useAuris().client.handleRedirectCallback().
Middleware (@auris/nextjs/middleware)
aurisMiddleware(config)
Protegge le route a livello Edge prima che raggiungano la tua applicazione. Valida il cookie di sessione dell’utente e reindirizza gli utenti non autenticati all’URL di login.
Firma:
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware(config: AurisMiddlewareConfig)Configurazione:
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
domain | string | obbligatorio | URL base dell’API Auris |
clientId | string | obbligatorio | Client ID OAuth |
tenant | string | 'default' | Nome del tenant/realm |
protectedPaths | string[] | [] | Percorsi che richiedono autenticazione. Match esatto, oppure match di prefisso con /* finale (es. '/dashboard/*') |
publicPaths | string[] | [] | Percorsi che saltano del tutto i controlli di autenticazione (stesse regole di match) |
loginUrl | string | '/login' | Dove reindirizzare gli utenti non autenticati. Il percorso richiesto in origine viene passato come ?callbackUrl= |
callbackPaths | string[] | tutti i percorsi protetti | Percorsi autorizzati a ricevere il callback OAuth2 (?code=&state=) senza autenticazione |
I pattern di percorso non sono espressioni regolari: un pattern corrisponde in modo esatto,
oppure come prefisso quando termina con /* ('/dashboard/*' corrisponde a /dashboard e a
tutto ciò che sta sotto).
// middleware.ts
import { aurisMiddleware } from '@auris/nextjs/middleware'
export default aurisMiddleware({
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
protectedPaths: [
'/dashboard/*',
'/impostazioni/*',
'/api/protetto/*',
],
publicPaths: [
'/',
'/about',
'/prezzi',
'/blog/*',
'/auth/*',
'/api/pubblico/*',
],
loginUrl: '/auth/login',
// Consenti il callback OAuth (?code=&state=) solo su questo percorso
callbackPaths: ['/auth/callback'],
})
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}Il modulo esporta anche sanitizeCallbackUrl(url), che restringe un valore callbackUrl a un
percorso relativo same-origin. Usalo nella pagina di login prima di reindirizzare al parametro
query callbackUrl scritto dal middleware:
import { sanitizeCallbackUrl } from '@auris/nextjs/middleware'
const target = sanitizeCallbackUrl(searchParams.get('callbackUrl') ?? '/')
router.replace(target)Helper Server (@auris/nextjs/server)
getSession(config)
Restituisce la sessione dell’utente in un Server Component o Route Handler. Legge il cookie accessToken e lo valida contro l’API Auris (o localmente, senza chiamate di rete, quando jwksUrl è impostato nella config o tramite la variabile d’ambiente AURIS_JWKS_URL).
Firma:
import { getSession } from '@auris/nextjs/server'
const session = await getSession({
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
}) // Promise<AurisSession | null>Restituisce:
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>Benvenuto, {session.firstName}</h1>
<p>La tua email: {session.email}</p>
<pre>{JSON.stringify(session.roles, null, 2)}</pre>
</div>
)
}withAuth(handler, config)
Funzione di ordine superiore che avvolge un Route Handler e inietta la sessione autenticata come req.session. Restituisce una risposta 401 se l’utente non è autenticato, e una risposta 403 se il permission opzionale della config non è concesso.
Firma:
import { withAuth } from '@auris/nextjs/server'
export const GET = withAuth(
async (req: AuthenticatedRequest) => Response, // req.session: AurisSession
{
domain: string, // obbligatorio
clientId: string, // obbligatorio
tenant?: string,
jwksUrl?: string,
permission?: string | string[], // controllo permessi opzionale (403 in caso di fallimento)
}
)// app/api/profilo/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 aggiornaProfilo(req.session.userId, body)
return Response.json(updated)
}, aurisConfig)requirePermission(permission, config, handler)
Come withAuth, ma applica anche un permesso specifico. Restituisce una risposta 403 se l’utente è autenticato ma non ha il permesso richiesto.
Firma:
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/documenti/[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 getDocumento(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 eliminaDocumento(id, req.session.userId)
return Response.json({ deleted: true })
}
)checkPermission(permission, config)
Restituisce un booleano che indica se l’utente corrente ha un permesso specifico (o tutti i permessi indicati quando si passa un array). Progettato per i Server Components dove hai bisogno di rendering condizionale basato sui permessi.
Firma:
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 } from '@auris/nextjs/server'
import { 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 puoGestireUtenti = await checkPermission('manage:users', aurisConfig)
const puoVedereReport = await checkPermission('view:reports', aurisConfig)
return (
<div>
<h1>Pannello Admin</h1>
{puoGestireUtenti && <GestioneUtenti />}
{puoVedereReport && <TabellaReport />}
{!puoGestireUtenti && !puoVedereReport && <p>Non hai accesso admin.</p>}
</div>
)
}createServerManagementClient(config?)
Crea un client per la Management API usando AURIS_CLIENT_SECRET dalle variabili d’ambiente. Nessuna configurazione richiesta se le variabili d’ambiente sono impostate; ogni campo può essere sovrascritto tramite l’argomento config opzionale.
Firma:
import { createServerManagementClient } from '@auris/nextjs/server'
const mgmt = createServerManagementClient()Il client si autentica con il grant OAuth2 client_credentials usando:
AURIS_DOMAIN(fallback suNEXT_PUBLIC_AURIS_URL)AURIS_CLIENT_ID(fallback suNEXT_PUBLIC_AURIS_CLIENT_ID)AURIS_CLIENT_SECRETAURIS_TENANT(default'default')
// app/api/admin/utenti/route.ts
import { createServerManagementClient } from '@auris/nextjs/server'
import { 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()
Crea un client FGA con un token di accesso M2M. Usalo nei Server Components e Route Handlers per eseguire controlli di autorizzazione Fine-Grained lato server.
Firma:
import { createServerFgaClient } from '@auris/nextjs/server'
const fga = await createServerFgaClient()// app/api/documenti/[id]/route.ts
import { withAuth } from '@auris/nextjs/server'
import { 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: 'Accesso negato' }, { status: 403 })
}
const doc = await getDocumento(docId)
return Response.json(doc)
}, {
domain: process.env.AURIS_DOMAIN!,
clientId: process.env.AURIS_CLIENT_ID!,
})Client Components
Tutti gli hook e i componenti di @auris/react sono ri-esportati da @auris/nextjs. Nei Client Components, importa da @auris/nextjs invece di @auris/react:
// Nei Client Components Next.js — usa @auris/nextjs, non @auris/react
'use client'
import { useAuris, useUser, usePermissions, AuthGuard, PermissionGate } from '@auris/nextjs'Consulta la pagina SDK React per il riferimento completo di tutti gli hook e componenti.
Esempio di Applicazione Completa
Un’applicazione Next.js minimale ma completa con autenticazione:
app/
layout.tsx — Layout root con AurisProvider
page.tsx — Home page pubblica
providers.tsx — Wrapper Client Component
auth/
login/page.tsx — Avvia il redirect di login
callback/page.tsx — Gestisce il redirect da Auris
dashboard/
page.tsx — Server Component protetto
settings/page.tsx — Protetto con controllo permessi
api/
profile/route.ts — Route API protetta
admin/
users/route.ts — Route API protetta da permessi
middleware.ts — Protezione Edge// 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="it">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}// 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 } from '@auris/nextjs/server'
import { 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>Benvenuto, {session.firstName}</h1>
{isAdmin && (
<a href="/dashboard/admin">Vai al Pannello Admin</a>
)}
</main>
)
}// 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,
firstName: req.session.firstName,
roles: req.session.roles,
})
}, aurisConfig)
export const PATCH = withAuth(async (req) => {
const body = await req.json()
const updated = await aggiornaProfilo(req.session.userId, body)
return Response.json(updated)
}, aurisConfig)// 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)
})Correlati
- SDK React — Hook e componenti ri-esportati da @auris/nextjs
- SDK JavaScript — SDK di basso livello alla base dei pacchetti React e Next.js
- Guida Login Ospitato — Dettagli sul flusso PKCE
- Guida Permessi — Riferimento RBAC
- Guida FGA — Autorizzazione Fine-Grained