المصادقة في Next.js 16 مع Auth.js v5: دليل عملي شامل لتسجيل الدخول والجلسات (2026)
دليل عملي وشامل لإعداد المصادقة في Next.js 16 باستخدام Auth.js v5: تسجيل الدخول عبر Google وGitHub وCredentials، إدارة الجلسات، حماية المسارات، وأمثلة كاملة قابلة للتشغيل.
المصادقة في Next.js 16 مع Auth.js v5 (الإصدار الجديد من NextAuth) تعتمد على ملف إعداد واحد auth.ts يصدّر دوال auth وsignIn وsignOut وhandlers، ويعمل مع App Router وServer Components وServer Actions بنفس التوقيع. في هذا الدليل أشرح خطوة بخطوة كيف أبني نظام مصادقة كامل: تسجيل دخول عبر مزودين خارجيين (Google وGitHub) أو ببريد وكلمة مرور (Credentials)، وإدارة الجلسات بـ JWT أو قاعدة بيانات عبر Prisma Adapter، وحماية المسارات في طبقة proxy.ts، والتحقق من المستخدم داخل Server Components وRoute Handlers، كل ذلك مع أمثلة قابلة للتشغيل في Next.js 16.
Auth.js v5 هو الاسم الرسمي الجديد لـ NextAuth، ويُثبَّت عبر npm install next-auth@beta ويصدّر API موحّد للـ App Router.
تعريف الإعداد يتم في ملف auth.ts في جذر المشروع، ويُستهلَك في app/api/auth/[...nextauth]/route.ts وفي proxy.ts وفي أي Server Component.
استراتيجية الجلسة الافتراضية JWT هي الأخف، وتتحوّل تلقائياً إلى جلسات قاعدة البيانات عند إضافة Adapter مثل Prisma أو Drizzle.
حماية المسارات تتم عبر دالة auth داخل proxy.ts في Next.js 16 (بديل middleware.ts) وتعمل على Edge Runtime بقيود محدودة على الحزم.
Server Actions تستدعي signIn وsignOut مباشرةً، وهذا يلغي الحاجة لمعالجات HTTP يدوية ويحسّن تجربة النماذج.
دائماً افصِل إعداد Auth.js إلى auth.config.ts خفيف الوزن لتجنّب استيراد Node-only APIs (مثل Prisma) داخل Edge Runtime.
ما الفرق بين Auth.js v5 و NextAuth؟
الإجابة المختصرة: Auth.js هو الاسم الجديد للمشروع، وv5 إصدار رئيسي يعيد تصميم API ليتوافق مع Next.js App Router وReact Server Components. حزمة npm لا تزال تُنشَر تحت اسم next-auth للحفاظ على التوافق، لكن المستندات والعلامة التجارية تحوّلت إلى authjs.dev. في الإصدار v4 كنّا نستورد getServerSession ونمرّر له خيارات في كل مكان. في v5 صار لدينا دالة auth() واحدة قادمة من ملف auth.ts المحلي، تعمل في Server Components وRoute Handlers و proxy.ts وServer Actions بنفس التوقيع تماماً.
ثمة فروق عملية أخرى تستحق الانتباه: v5 يدعم Server Actions أصلاً عبر signIn وsignOut بدل الاعتماد على hooks العميل فقط، ويفصل إعداد المزوّدين عن إعداد الـ Adapter ليُسهّل التشغيل في Edge Runtime. ما زال v4 يحصل على تصحيحات أمان، لكن أي مشروع Next.js 16 جديد يجب أن يبدأ مباشرةً بـ v5. صدّقني، الترقية لاحقاً تتطلّب إعادة كتابة كل استدعاءات الجلسة وملفات الإعداد، وقد دفعت هذه الضريبة في مشروعين سابقين.
تثبيت Auth.js v5 في مشروع Next.js 16
أبدأ دائماً بمشروع Next.js 16 نظيف يستخدم App Router و TypeScript. التثبيت يحتاج حزمة واحدة فقط، ثم توليد مفتاح سرّي للجلسات. إذا أردت مزوّدين عبر OAuth، فهذا كل ما يلزم. Prisma Adapter اختياري وسأضيفه لاحقاً عند الحديث عن جلسات قاعدة البيانات. في تجربتي، أكبر سبب لفشل أول إعداد هو نسيان متغيّر البيئة AUTH_SECRET أو وضع قيمة AUTH_URL غير صحيحة عند النشر على Vercel.
# 1) إضافة الحزمة
npm install next-auth@beta
# 2) توليد سر للجلسات (32 بايت Base64)
npx auth secret
# سيُضاف المفتاح تلقائياً إلى .env.local باسم AUTH_SECRET
بعد التثبيت، أنشئ ملفّين رئيسيين: auth.config.ts يحوي إعداداً خفيفاً متوافقاً مع Edge، وauth.ts يستورد الإعداد ويضيف Adapter ومزوّدات تعتمد على Node. هذا الفصل ليس تجميلياً، بل هو السبب الوحيد الذي يمنع proxy.ts من رمي خطأ "can't use Node APIs in Edge" عند النشر. هذه نقطة هدرت فيها ساعتين كاملتين أول مرة جربت v5، فلا تكرّر خطأي.
// app/api/auth/[...nextauth]/route.ts
export { GET, POST } from "@/auth";
// handlers مُصدَّرة بأسماء HTTP، وهذا كل ما يحتاجه App Router
إعداد المزوّدين: Google و GitHub و Credentials
Auth.js v5 يدعم أكثر من 70 مزوّد OAuth جاهز، إضافةً إلى مزوّد Credentials لتسجيل دخول ببريد وكلمة مرور. لتفعيل Google، أضف AUTH_GOOGLE_ID وAUTH_GOOGLE_SECRET في .env.local، وAuth.js يقرأها تلقائياً دون تمرير صريح. نفس الأمر مع GitHub: AUTH_GITHUB_ID وAUTH_GITHUB_SECRET. عند النشر، أضف AUTH_TRUST_HOST=true إذا كنت خلف بروكسي مثل Vercel (يتم تلقائياً) أو Cloudflare.
مزوّد Credentials أعقد قليلاً لأنه يتطلّب التحقّق اليدوي من كلمة المرور. أنصح باستخدام Zod للتحقّق من الحقول وbcrypt لمطابقة الهاش. في المشاريع التي أعمل عليها، أضع التحقّق دائماً في طبقة منفصلة تُستدعى من authorize لتسهيل اختبارها:
// auth.ts (إضافة Credentials)
import Credentials from "next-auth/providers/credentials";
import { z } from "zod";
import bcrypt from "bcryptjs";
import { getUserByEmail } from "@/lib/users";
const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
providers: [
Google,
GitHub,
Credentials({
async authorize(credentials) {
const parsed = loginSchema.safeParse(credentials);
if (!parsed.success) return null;
const { email, password } = parsed.data;
const user = await getUserByEmail(email);
if (!user?.passwordHash) return null;
const match = await bcrypt.compare(password, user.passwordHash);
if (!match) return null;
return { id: user.id, email: user.email, name: user.name };
},
}),
],
تسجيل الدخول والخروج عبر Server Actions
إحدى أجمل ميزات v5 هي القدرة على استدعاء signIn داخل Server Actions في Next.js مباشرةً، بدل الاعتماد على hooks العميل. هذا يُبسّط النماذج كثيراً ويمنحك أمان CSRF مدمج عبر useFormState. الميزة الإضافية أن المعالج كاملاً يعمل على الخادم، لذا تستطيع رمي redirect() مباشرةً بعد نجاح المصادقة دون قفز مزدوج.
// app/actions/auth.ts
"use server";
import { signIn, signOut } from "@/auth";
import { AuthError } from "next-auth";
export async function loginAction(
prevState: string | undefined,
formData: FormData
) {
try {
await signIn("credentials", {
email: formData.get("email"),
password: formData.get("password"),
redirectTo: "/dashboard",
});
} catch (error) {
if (error instanceof AuthError) {
switch (error.type) {
case "CredentialsSignin":
return "بيانات الدخول غير صحيحة.";
default:
return "حدث خطأ غير متوقّع.";
}
}
throw error; // مهم: لا تبتلع أخطاء redirect
}
}
export async function logoutAction() {
await signOut({ redirectTo: "/" });
}
ثم في النموذج (Client Component) أربطه بـ useActionState الجديد في React 19 الذي يأتي مع Next.js 16:
للخروج، يكفي زر بسيط داخل form يستدعي logoutAction. لا حاجة لاستيراد signOut من جانب العميل، وهذا يقلّل حجم حزمة JavaScript بشكل ملموس.
استراتيجية الجلسات: JWT مقابل قاعدة البيانات
السؤال المتكرر: متى أستخدم JWT ومتى أستخدم جلسات قاعدة البيانات؟ الجدول التالي يلخّص الفروق العملية كما أراها بعد سنوات من استخدام كلا الخيارين في الإنتاج:
الميزة
JWT (الافتراضي)
قاعدة بيانات (عبر Adapter)
التوافق مع Edge Runtime
كامل
يحتاج Adapter يدعم Edge
قراءة الجلسة
فكّ تشفير محلي
استعلام قاعدة بيانات
إبطال فوري للجلسة
صعب (يتطلّب قائمة سوداء)
سهل (احذف الصفّ)
حجم الكوكي
كبير (1–4KB)
صغير (~100 بايت)
دعم مزوّد Credentials
نعم
لا (محدودية تصميمية)
الأنسب لـ
تطبيقات SaaS وEdge
تطبيقات حسّاسة أمنياً
للجلسات في قاعدة البيانات، أنصح بـ Prisma Adapter الذي يدعم PostgreSQL وMySQL وSQLite. الإعداد ثلاث خطوات: تثبيت الحزمة، إضافة جداول Auth.js إلى المخطّط، ثم تمرير Adapter في auth.ts:
في Next.js 16، طبقة middleware.ts أُعيدت تسميتها إلى proxy.ts مع توسيع للـ API. حماية المسارات تتم عبر تصدير auth كـ default، فتصبح كل المسارات المحدّدة في matcher محميّة تلقائياً. أعمل دائماً مع auth.config.ts الخفيف هنا، تجنّباً لأي استيراد لـ Prisma أو Node APIs. للتفاصيل الكاملة راجع دليل Middleware و proxy.ts في Next.js 16.
المنطق نفسه (هل المسار يبدأ بـ /dashboard؟) موجود في callback authorized داخل auth.config.ts. هذا الفصل يسمح بإضافة مسارات محميّة جديدة بتعديل سطر واحد فقط، دون لمس proxy.ts. تذكّر أن proxy.ts يعمل على Edge Runtime، فأي استيراد لـ bcryptjs أو Prisma Client سيُحطّم البناء، وهذا تحديداً ما يحلّه نمط الفصل بين auth.ts وauth.config.ts.
قراءة الجلسة داخل Server Components
أحد أكبر تحسينات v5 هو أن دالة auth() تعمل من أي مكان: Server Component، Route Handler، Server Action، أو proxy.ts. لا حاجة لتمرير req أو res. هذا يجعل عرض البيانات المخصّصة للمستخدم بسيطاً للغاية:
// 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 (
<main>
<h1>مرحباً {session.user.name}</h1>
<p>بريدك: {session.user.email}</p>
</main>
);
}
للحصول على بيانات المستخدم في Client Components، استخدم SessionProvider من next-auth/react مع hook useSession. لكن في معظم الحالات، تمرير البيانات الحساسة كـ props من Server Component يكون أسرع وأكثر أماناً. أتجنّب SessionProvider إلا عند الحاجة للتحديث المباشر بعد تغيير الحالة.
صلاحيات الأدوار (RBAC) وتخصيص JWT
تخصيص الـ JWT لإضافة دور (role) أو معرّف تنظيمي (organizationId) يتم في callbacks jwt وsession. هذه أهم نقطة في توسيع نظام المصادقة لتطبيقات SaaS. كل التحكّم بالصلاحيات يبدأ من هنا، وأنصح بأن تضع البنية الأولى منذ اليوم الأوّل بدلاً من إضافتها لاحقاً (تعلّمت ذلك بالطريقة الصعبة).
// auth.ts
callbacks: {
async jwt({ token, user, trigger, session }) {
if (user) {
token.role = user.role; // أوّل تسجيل دخول
}
if (trigger === "update" && session?.role) {
token.role = session.role; // عند update() من العميل
}
return token;
},
async session({ session, token }) {
if (token.role && session.user) {
session.user.role = token.role as "admin" | "user";
}
return session;
},
},
الآن أي Server Component يستدعي auth() يحصل على session.user.role مع تلميحات نوع كاملة، ويمكنك بناء حواجز صلاحيات أنيقة:
const session = await auth();
if (session?.user.role !== "admin") {
return <p>لا تملك صلاحية الوصول</p>;
}
مزالق Edge Runtime وكيف تتجنّبها
Edge Runtime يقيّد API JavaScript المتاحة، فلا يدعم Node modules الكاملة مثل fs أو crypto الأصلي بنفس واجهة Node، ولا يدعم WASM ثقيلاً. أكثر خطأ أراه عند مراجعة مشاريع المتعلّمين هو استيراد Prisma أو bcrypt مباشرةً في proxy.ts. يعمل محلياً، ثم يفشل عند البناء للنشر. الحل دائماً هو نمط auth.config.ts الخفيف.
مزلق آخر: مزوّد Credentials يستخدم bcrypt الذي لا يعمل على Edge. الحل الذي أعتمده هو وضع export const runtime = "nodejs" في Route Handler الخاص بالمصادقة، أو ترقية إلى @node-rs/bcrypt الذي يعمل في كلا البيئتين. للتفاصيل الرسمية، راجع وثائق المصادقة في Next.js.
الأسئلة الشائعة
هل NextAuth ما زال مدعوماً ويتلقى تحديثات؟
نعم، NextAuth أصبح يحمل اسم Auth.js وما زال يتلقّى تحديثات نشطة. الإصدار v5 (المنشور تحت اسم next-auth@beta) هو ما ينصح به فريق Vercel وفريق Next.js للمشاريع الجديدة. الإصدار v4 يحصل على إصلاحات أمان فقط.
هل أستطيع استخدام Auth.js دون قاعدة بيانات؟
نعم تماماً. مع استراتيجية JWT الافتراضية لا تحتاج إلى قاعدة بيانات، وكل بيانات الجلسة تُخزَّن في كوكي مشفّر. هذا الخيار مثالي لتطبيقات OAuth خفيفة الوزن، لكنك تفقد القدرة على ربط حسابات متعدّدة بنفس المستخدم تلقائياً.
كيف أنفّذ تسجيل خروج فوري من جميع الأجهزة؟
هذه أهم قيود JWT: إبطال فوري للجلسة يتطلّب جلسات قاعدة البيانات. أبسط حل هو استخدام Prisma Adapter مع session.strategy = "database" ثم حذف الصفوف من جدول Session. كحل وسط، يمكن إضافة tokenVersion في User ومقارنته داخل callback الجلسة.
لماذا أحصل على خطأ "Configuration" عند نشر التطبيق؟
السبب الأكثر شيوعاً هو غياب AUTH_SECRET في بيئة الإنتاج، أو عدم تطابق AUTH_URL مع الدومين الفعلي. تأكّد أيضاً من إضافة عناوين callback في لوحات Google Cloud وGitHub OAuth Apps (مثل https://your-domain.com/api/auth/callback/google).
هل يدعم Auth.js v5 المصادقة بعاملين (2FA)؟
لا يوجد دعم مدمج لـ 2FA حتى الآن، لكن النمط الموصى به هو إضافة خطوة TOTP بعد نجاح signIn الأوّل: خزّن twoFactorVerified: false في JWT، وأعد التوجيه إلى صفحة إدخال الرمز، ثم حدّث الجلسة عبر update() بعد التحقّق. مكتبات مثل otplib تعمل جيداً لهذا الغرض.
كل ما تحتاجه لتفعيل PPR في Next.js 16 خطوة بخطوة: التكوين، حدود Suspense، الفرق عن ISR وSSR، الدمج مع use cache، أخطاء شائعة، ونصائح نشر على Vercel و Node.js و Edge.
دليل عملي شامل لـ Streaming و Suspense و loading.tsx في Next.js 16. تعلم بناء واجهات سريعة الاستجابة مع أمثلة كود حقيقية، حل مشكلة الـ key، التكامل مع Cache Components، وأفضل ممارسات الأداء لعام 2026.
دليل عملي لنظام التخزين المؤقت الجديد في Next.js 16. تعرّف على توجيه use cache والتحكم في مدة التخزين مع cacheLife ووسم البيانات مع cacheTag وإبطال التخزين باستخدام revalidateTag و updateTag مع أمثلة تطبيقية جاهزة.