אימות ב-Next.js 16 עם Auth.js v5: מדריך מלא ל-App Router

מדריך מלא ל-Auth.js v5 ב-Next.js 16 App Router: הקמה מ-zero ל-production עם JWT sessions, OAuth (Google ו-GitHub), Credentials provider עם Server Actions, והגנת נתיבים דרך proxy.ts. כולל split config וצ'קליסט production.

אימות Auth.js v5 ב-Next.js 16: מדריך 2026

עודכן: 30 במאי 2026

אימות ב-Next.js 16 עם Auth.js v5 הוא הדרך הרשמית והמומלצת לטיפול במשתמשים ב-App Router. השילוב המנצח: הפונקציה auth() ב-Server Components, proxy.ts להגנה על נתיבים, ו-Server Actions לטפסי התחברות. Auth.js v5 (שמו הקודם NextAuth.js) הוא הפתרון הרשמי המומלץ בתיעוד של Next.js, תומך באופן מלא ב-App Router וב-React 19, ועובד גם ב-Edge Runtime וגם ב-Node.js Runtime. במדריך הזה אסקור הקמה מלאה מ-zero ל-production, כולל JWT לעומת database sessions, OAuth, credentials, והגנת נתיבים.

  • Auth.js v5 מחליף את getServerSession() בפונקציה אחת, auth(), שעובדת ב-Server Components, ב-Route Handlers, ב-Server Actions וב-proxy.
  • הקובץ proxy.ts (לשעבר middleware.ts עד Next.js 15) הוא המקום הנכון להגנת נתיבים, אבל עליו לרוץ ב-Edge Runtime ולכן נדרש פיצול הקונפיגורציה.
  • JWT sessions הם ברירת המחדל ב-2026 בגלל תאימות מלאה ל-Edge. database sessions דורשים adapter (Prisma או Drizzle) ולא ניתן לקרוא להם מ-proxy.
  • Server Actions עם signIn() ו-signOut() הן הדרך המודרנית לטפסי התחברות, בלי useSession() בצד הלקוח.
  • קונפיגורציה מינימלית דורשת AUTH_SECRET, ספק אחד לפחות, ופונקציית authorized ב-callbacks להגנת נתיבים מ-proxy.

למה Auth.js v5 ב-Next.js 16

הייתי עם NextAuth.js מאז גרסה 3, כשעוד היה pages/api/auth/[...nextauth].ts ו-getSession() שהחזיר null בלי להסביר למה. גרסה 5, שהפכה ליציבה בסוף 2024 ושופרה משמעותית במהלך 2025 ו-2026, היא קפיצת מדרגה אמיתית. API אחיד, תמיכה מובנית ב-App Router, ועבודה חלקה עם Edge Runtime. אם אתם ב-Next.js 16, אין סיבה לא להשתמש בה.

השינוי המרכזי לעומת v4 הוא איחוד הקונפיגורציה לקובץ auth.ts אחד שמייצא ארבעה דברים: handlers (ל-Route Handlers), auth (לקריאה ל-session מכל מקום), signIn ו-signOut (ל-Server Actions). הפונקציה getServerSession() פשוט נעלמה, וזה דבר טוב. היא הייתה גורם בלבול ענקי בקוד שלי עד היום.

תאימות חשובה: Auth.js v5 עובד עם React 19 ועם Next.js 16 (release notes) ללא תיקונים. כן צריך לזכור שאם השתמשתם ב-middleware.ts בעבר, ב-Next.js 16 הוא קיבל את השם proxy.ts, ויש מדריך מעבר מ-middleware ל-proxy שמראה את ההבדלים המלאים.

התקנה וקונפיגורציה ראשונית

ההתקנה ב-2026 קצרה. צריך חבילה אחת, קובץ קונפיגורציה אחד, וסוד אחד.

npm install next-auth@beta
# הסוד מיוצר אוטומטית עם:
npx auth secret

הפקודה npx auth secret תוסיף AUTH_SECRET ל-.env.local שלכם. זהו ה-secret שמשמש לחתימה על JWT. אם הוא דולף, כל ה-session tokens שלכם נחשפים, אז אל תכניסו אותו ל-git.

הקובץ הראשי, auth.ts בשורש הפרויקט, נראה ככה במינימום:

// auth.ts
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [GitHub],
})

ועוד שני קבצים קטנים מחברים את הכל:

// app/api/auth/[...nextauth]/route.ts
export { GET, POST } from "@/auth"
export const runtime = "nodejs" // חשוב: לא edge ברמת ה-route handler

הוספת OAuth providers (Google, GitHub)

OAuth ב-Auth.js v5 הוא ה-flow שהכי קל להפעיל. שלוש שורות לכל provider. ב-Next.js 16, ה-callback URL הוא /api/auth/callback/[provider], וזה הערך שצריך להזין בדשבורד של ה-provider (Google Cloud Console, GitHub Developer Settings וכו').

// auth.ts
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"
import Google from "next-auth/providers/google"

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [
    GitHub({
      clientId: process.env.AUTH_GITHUB_ID,
      clientSecret: process.env.AUTH_GITHUB_SECRET,
    }),
    Google({
      clientId: process.env.AUTH_GOOGLE_ID,
      clientSecret: process.env.AUTH_GOOGLE_SECRET,
    }),
  ],
  pages: {
    signIn: "/login",
  },
})

שימו לב לקונבנציית שמות משתני הסביבה: AUTH_[PROVIDER]_ID ו-AUTH_[PROVIDER]_SECRET. אם תשתמשו בדיוק בשמות האלה, Auth.js יקרא אותם אוטומטית ותוכלו להשמיט את ה-clientId וה-clientSecret מהקונפיגורציה. אני אישית מעדיף לכתוב אותם במפורש כי זה מקל על debugging כשמשהו נשבר ב-CI.

כפתור התחברות הוא Server Action פשוט. בלי useState, בלי fetch, בלי טיפול ב-redirects ידני:

// app/login/page.tsx
import { signIn } from "@/auth"

export default function LoginPage() {
  return (
    <form
      action={async () => {
        "use server"
        await signIn("github", { redirectTo: "/dashboard" })
      }}
    >
      <button type="submit">התחבר עם GitHub</button>
    </form>
  )
}

Credentials provider עם Server Actions

אם אתם מנהלים סיסמאות בעצמכם, וזו תמיד אחריות גדולה, תצטרכו את ה-Credentials provider. הוא לא נתמך עם database sessions בלי תוספות, אבל עם JWT הוא עובד נהדר. הדפוס שאני ממליץ עליו: validation עם zod, השוואת hash עם bcrypt, והחזרת אובייקט user או null.

// auth.ts (חלקי)
import Credentials from "next-auth/providers/credentials"
import { z } from "zod"
import bcrypt from "bcryptjs"
import { getUserByEmail } from "@/lib/users"

const schema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
})

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [
    Credentials({
      async authorize(credentials) {
        const parsed = schema.safeParse(credentials)
        if (!parsed.success) return null

        const user = await getUserByEmail(parsed.data.email)
        if (!user) return null

        const ok = await bcrypt.compare(parsed.data.password, user.passwordHash)
        if (!ok) return null

        return { id: user.id, email: user.email, name: user.name }
      },
    }),
  ],
  session: { strategy: "jwt" },
})

טופס ההתחברות בצד הלקוח הוא שוב Server Action, בלי "use client" מיותר. השילוב טבעי עם המדריך המלא ל-Server Actions ב-Next.js 16 שמסביר בהרחבה את ה-API החדש של useActionState לטיפול בשגיאות.

// app/login/credentials-form.tsx
import { signIn } from "@/auth"
import { AuthError } from "next-auth"

async function login(formData: FormData) {
  "use server"
  try {
    await signIn("credentials", {
      email: formData.get("email"),
      password: formData.get("password"),
      redirectTo: "/dashboard",
    })
  } catch (error) {
    if (error instanceof AuthError) {
      return { error: "פרטי ההתחברות שגויים" }
    }
    throw error // חשוב: redirect זורק שגיאה, תן לה לעבור
  }
}

איך להגן על נתיבים ב-Next.js 16 App Router

הגנת נתיבים היא היכן ש-Auth.js v5 באמת בולט. במקום middleware שקורא לדאטהבייס בכל request (יקר, איטי, בלתי אפשרי ב-Edge), הוא מציע דפוס split config: קונפיג מלא ל-server, קונפיג רזה ל-proxy.

// auth.config.ts — חייב להיות Edge-compatible
import type { NextAuthConfig } from "next-auth"

export const authConfig = {
  pages: { signIn: "/login" },
  providers: [], // יוזרק ב-auth.ts המלא
  callbacks: {
    authorized({ auth, request: { nextUrl } }) {
      const isLoggedIn = !!auth?.user
      const isOnDashboard = nextUrl.pathname.startsWith("/dashboard")

      if (isOnDashboard) return isLoggedIn
      if (isLoggedIn && nextUrl.pathname === "/login") {
        return Response.redirect(new URL("/dashboard", nextUrl))
      }
      return true
    },
  },
} satisfies NextAuthConfig
// proxy.ts (ב-Next.js 16, השם החדש של middleware.ts)
import NextAuth from "next-auth"
import { authConfig } from "./auth.config"

export const { auth: middleware } = NextAuth(authConfig)

export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}

הקובץ auth.ts המלא מייבא את authConfig ומוסיף providers ו-callbacks כבדים יותר שלא יכולים לרוץ ב-Edge (למשל ה-Credentials עם bcrypt). זה הדפוס הרשמי שמופיע ב-תיעוד הרשמי של Auth.js, וזה גם מה שיגרום למשתמשים מוגנים לא מאומתים לקבל 307 redirect מיידי בלי round trip לדאטהבייס.

JWT לעומת Database Sessions

שאלה חוזרת. הנה ההבדלים בטבלה ברורה:

תכונה JWT (ברירת מחדל) Database
ביצועיםללא קריאה ל-DB ב-proxyקריאה לכל request
Edge Runtimeתומך מלאלא נתמך ב-proxy
ביטול session מיידיקשה (צריך blacklist)קל (מחיקה מה-DB)
גודל cookieגדל עם dataקטן (id בלבד)
תאימות Credentialsתמיכה מלאהנדרשת התאמה
שמירת user data רגישחשוף בצד לקוחנשאר ב-server

שורה תחתונה: התחילו עם JWT אלא אם יש לכם דרישה ספציפית לביטול sessions באופן מיידי (למשל banking או admin tools). פעם אחת עברתי אפליקציה מ-JWT ל-database sessions אחרי שהיה לנו אירוע אבטחה, וזה היה כאב ראש של שבועיים. אם אתם בונים מאפס ויש לכם שום ספק, JWT הוא הבחירה הנכונה ב-2026.

קריאה ל-session ב-React Server Components

בעולם ה-App Router, רוב הזמן אתם רוצים לקרוא session ב-Server Component, לא בצד הלקוח. ה-API פשוט להחריד:

// app/dashboard/page.tsx
import { auth } from "@/auth"
import { redirect } from "next/navigation"

export default async function DashboardPage() {
  const session = await auth()

  if (!session?.user) {
    redirect("/login")
  }

  return (
    <div>
      <h1>שלום, {session.user.name}</h1>
      <p>Email: {session.user.email}</p>
    </div>
  )
}

הפונקציה auth() פנימית מבצעת deduplication דרך ה-cache של React 19, כך שגם אם תקראו לה ב-10 קומפוננטות, יש רק קריאה אחת לפיצוח ה-JWT לכל request. אין צורך ב-Context, אין צורך ב-Provider, ואין hydration mismatch. זה אחד הדברים שגרמו לי סוף סוף לחבב את ה-App Router אחרי שנים של עבודה עם pages router.

לעדכון session בעקבות שינוי נתונים (למשל אחרי עדכון פרופיל), השתמשו ב-callback jwt כדי לרענן את ה-token, ובצד הלקוח קראו ל-useSession() עם update(). לעבודה עם נתונים שמשתנים תכופות, כמו תפקידי משתמש, שילוב נכון של auth עם Cache Components ו-cacheTag ב-Next.js 16 נותן ביצועים מצוינים.

צ'קליסט production

לפני שדוחפים ל-production, עברו על הרשימה הקצרה הזו. ראיתי כל אחד מהפריטים האלה נופל בפועל באפליקציות חיות:

  • AUTH_SECRET: לפחות 32 בתים אקראיים, יוצר ב-npx auth secret. שונה לחלוטין בין סביבות.
  • AUTH_URL או AUTH_TRUST_HOST=true: נדרש מאחורי reverse proxy כמו Vercel או Cloudflare כדי שה-callbacks יבנו URL נכון.
  • HTTPS בלבד: cookies של session מסומנים כ-Secure ב-production. בדיקה ב-HTTP פשוט לא תעבוד.
  • Cookie SameSite: ברירת המחדל היא lax. אם אתם משלבים iframes או cross-domain, תצטרכו none בתוספת שיקולי CSRF נוספים.
  • CSRF protection: מובנה ב-Auth.js, אבל אם אתם פותחים endpoints מותאמים אישית, ודאו שיש להם הגנת CSRF נפרדת או שהם דורשים SameSite=lax.
  • Rate limiting על Credentials: הסיוט של brute force. שלבו עם Upstash Redis או דומה ב-proxy לפני שאתם מגיעים ל-signIn().
  • Database adapter ב-Node runtime בלבד: אם אתם משתמשים ב-Prisma או Drizzle, ה-Route Handlers שלהם חייבים export const runtime = "nodejs".

שאלות נפוצות

האם Auth.js v5 מוכן ל-production ב-2026?

כן. הגרסה הראשונה היציבה של v5 פורסמה בסוף 2024, ומאז 2025 היא מטופלת באפליקציות גדולות כולל באתרים של Vercel עצמה. עדיין מומלץ לעגן גרסת patch ספציפית כי קצב השינויים גבוה מ-v4.

מה ההבדל בין Auth.js ל-NextAuth.js?

זה אותו פרויקט. NextAuth.js v4 שונה שמו ל-Auth.js בגרסה v5 כדי לציין שהוא תומך גם ב-frameworks אחרים (SvelteKit, SolidStart, Express). בעולם של Next.js, חבילת ה-npm עדיין נקראת next-auth.

איך מגנים על נתיבים ב-Next.js 16 בלי middleware?

ב-Next.js 16, הקובץ middleware.ts שונה שמו ל-proxy.ts. הוא רץ ב-Edge Runtime וקורא ל-auth() מתוך Auth.js עם split config כדי להחליט אם לתת גישה. נתיבים מוגנים מקבלים 307 redirect ל-/login.

האם Auth.js עובד עם Server Actions?

כן, ולמעשה זו הדרך המומלצת ב-2026. הפונקציות signIn() ו-signOut() מ-auth.ts מיועדות לשימוש ישיר בתוך Server Actions, ללא צורך ב-useSession() או fetch ל-API route ידני.

Auth.js או Clerk או Lucia, איזה לבחור?

Auth.js הוא חינמי ושולט בכל הקוד, אבל דורש קצת עבודה. Clerk הוא מנוהל, עם ממשק יפה, ויקר. Lucia היה סופר רזה אבל התחזוקה הופסקה בסוף 2024 ולא מומלץ לפרויקטים חדשים. ב-2026, Auth.js היא ברירת המחדל הסבירה אלא אם אתם מוכנים לשלם על UX מנוהל מלא.

Ben Howard
אודות הכותב Ben Howard

Full-stack Next.js developer who's been with the framework since pages-only days. Slowly warming up to App Router.