Session lesen mit auth()
Jetzt zahlt sich die Vereinheitlichung aus: In Server Components, Route Handlers und Server Actions schreibst du immer const session = await auth(). Nur der Client tanzt aus der Reihe — dort gibt es weiterhin den reaktiven Hook useSession().
Faustregel: Liest du serverseitig (Server Component, Action, Handler), nimm
auth(). Brauchst du den Login-Status reaktiv im Browser (z.B. ein Avatar im Header, der sofort umschaltet), nimm useSession() — und wickle die App in einen SessionProvider.Server Component — der Normalfall
app/profil/page.tsx
import { auth } from "@/auth";
export default async function Profil() {
const session = await auth();
if (!session) return <p>Nicht eingeloggt.</p>;
return <p>Hallo, {session.user?.name}!</p>;
}Route Handler — gleiche Funktion
app/api/me/route.ts
import { auth } from "@/auth";
export const GET = auth((req) => {
if (!req.auth) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
return Response.json({ user: req.auth.user });
});Wickelst du den Handler in auth(...), hängt die Session direkt an req.auth — kein separater Aufruf nötig. Du könntest stattdessen auch hier await auth() rufen.
Client — der reaktive Hook
Der Hook braucht Kontext. Einmal pro App den Provider setzen, dann ist useSession() überall im Client-Tree verfügbar:
app/providers.tsx
"use client";
import { SessionProvider } from "next-auth/react";
export function Providers({ children }: { children: React.ReactNode }) {
return <SessionProvider>{children}</SessionProvider>;
}eine Client-Komponente
"use client";
import { useSession } from "next-auth/react";
export function Avatar() {
const { data: session, status } = useSession();
if (status === "loading") return <Spinner />;
return session ? <img src={session.user?.image ?? ""} /> : null;
}Wer was benutzt
Server: await auth()
Server Components · Route Handlers · Server Actions · Middleware. Synchron-fühlend, läuft vor dem Rendern, kein Provider nötig.
Client: useSession()
Nur in
"use client"-Komponenten, braucht SessionProvider, dafür reaktiv: ändert sich der Login-Status, rendert die Komponente neu.Warum eigentlich? — Warum auth() im Server fast immer reicht
Im App Router rendern Server Components vor der Auslieferung. Du kennst den Login-Status also schon beim Rendern und kannst direkt das richtige UI schicken — ohne Flackern, ohne Lade-Spinner, ohne dass das JWT je den Browser erreicht.
useSession() brauchst du nur, wenn sich der Status im laufenden Client ändern soll, ohne die Seite neu zu laden.Häufiger Denkfehler — auth() im Client aufrufen
auth() ist eine Server-Funktion. Importierst du sie in eine "use client"-Komponente, bekommst du einen Build- oder Runtime-Fehler. Umgekehrt gilt dasselbe: useSession() ist ein React-Hook und funktioniert nur im Client mit Provider. Merksatz: auth() = Server, useSession() = Client.Tiefer rein — Was im Session-Objekt steckt — und wie du es erweiterst
Standardmäßig enthält
session.user nur name, email und image. Willst du z.B. eine Rolle oder die User-ID mitführen, reichst du sie über die jwt- und session-Callbacks durch: im jwt-Callback ins Token schreiben, im session-Callback von dort aufs Session-Objekt heben. Per Module-Augmentation kannst du den Session-Typ dann TypeScript-sauber erweitern.