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 Denkfehlerauth() 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 reinWas 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.