الخطوات
-
1
ثبّت Auth.js الإصدار 5
Auth.js v5 منشور باسم
next-auth@beta. ثبّته وأنشئ سرًا — هذا السر يوقّع token الجلسة ويجب أن يبقى خارج نظام التحكم بالإصدارات.bashnpm install next-auth@beta # أنشئ AUTH_SECRET عشوائيًا واكتبه في .env.local npx auth secret # يضيف تلقائيًا: AUTH_SECRET="<random>" إلى .env.local -
2
أنشئ ملف إعداد auth.ts
أنشئ
auth.tsفي جذر المشروع (بجانبpackage.json). هذا الملف هو المصدر الوحيد للحقيقة — يصدّرauthوsignInوsignOutوhandlers. كل شيء آخر يستورد منه مباشرةً لا منnext-auth.typescript// auth.ts import NextAuth from "next-auth" import Google from "next-auth/providers/google" export const { handlers, signIn, signOut, auth } = NextAuth({ providers: [ Google({ clientId: process.env.AUTH_GOOGLE_ID, clientSecret: process.env.AUTH_GOOGLE_SECRET, }), ], }) -
3
اربط معالج مسار API
يحتاج Auth.js إلى مسار catch-all على
/api/auth/[...nextauth]لمعالجة OAuth callbacks وتسجيل الدخول والخروج ونقاط نهاية الجلسة. أنشئ الملف وأعد تصدير الـ handlers من ملف الإعداد.typescript// app/api/auth/[...nextauth]/route.ts import { handlers } from "@/auth" export const { GET, POST } = handlers -
4
أضف متغيرات البيئة المطلوبة
أضف هذه المتغيرات إلى
.env.local. للحصول على بيانات Google، اذهب إلى Google Cloud Console تحت APIs & Services → Credentials → OAuth 2.0 Client IDs. اضبط redirect URI المصرّح به علىhttp://localhost:3000/api/auth/callback/googleللتطوير (وأضف رابط الإنتاج بشكل منفصل).bash# .env.local AUTH_SECRET="generated-by-npx-auth-secret" AUTH_GOOGLE_ID="your-google-client-id.apps.googleusercontent.com" AUTH_GOOGLE_SECRET="your-google-client-secret" # NEXTAUTH_URL غير مطلوب في v5 — Auth.js يستنتجه من الطلب -
5
احمِ Server Components بـ auth()
في أي Server Component أو Server Action، استدعِ
auth()للحصول على الجلسة. تُعيدnullعندما لا يكون المستخدم مسجلًا دخوله. أعِد التوجيه أو اعرض بوابة دخول بناءً على ذلك.typescript// app/dashboard/page.tsx import { auth } from "@/auth" import { redirect } from "next/navigation" export default async function DashboardPage() { const session = await auth() if (!session) { redirect("/api/auth/signin") } return ( <main> <h1>Welcome, {session.user?.name}</h1> </main> ) } -
6
أضف SessionProvider للمكونات العميلة
المكونات العميلة لا تستطيع استدعاء
auth()— تستخدم بدلًا من ذلك hook باسمuseSession(). لفّ layout الجذر بـSessionProviderحتى يعمل الـ hook في أي مكان في شجرة العميل.typescript// app/layout.tsx import { SessionProvider } from "next-auth/react" import { auth } from "@/auth" export default async function RootLayout({ children }: { children: React.ReactNode }) { const session = await auth() return ( <html> <body> <SessionProvider session={session}> {children} </SessionProvider> </body> </html> ) } // في أي مكون عميل: "use client" import { useSession } from "next-auth/react" export function UserAvatar() { const { data: session, status } = useSession() if (status === "loading") return <span>Loading…</span> if (!session) return <a href="/api/auth/signin">Sign in</a> return <img src={session.user?.image ?? ""} alt={session.user?.name ?? ""} /> } -
7
أضف أزرار تسجيل الدخول والخروج
استورد
signInوsignOutمن ملفauth.tsواستدعهما من Server Actions داخل<form>. هذا يمنع كشف بيانات الاعتماد للعميل ويعمل حتى بدون JavaScript.typescript// components/auth-buttons.tsx import { signIn, signOut } from "@/auth" export function SignInButton() { return ( <form action={async () => { "use server"; await signIn("google") }}> <button type="submit">Sign in with Google</button> </form> ) } export function SignOutButton() { return ( <form action={async () => { "use server"; await signOut() }}> <button type="submit">Sign out</button> </form> ) } -
8
احمِ المسارات بـ middleware
أنشئ ملف
middleware.tsفي جذر المشروع. صدّر دالةauthكـ middleware — ستعترض كل طلب يطابق إعدادmatcherوتعيد توجيه المستخدمين غير الموثّقين إلى صفحة تسجيل الدخول قبل أن يُنفَّذ معالج المسار.typescript// middleware.ts export { auth as middleware } from "@/auth" export const config = { matcher: [ // احمِ كل شيء تحت /dashboard و/account "/dashboard/:path*", "/account/:path*", // تخطَّ الملفات الثابتة ومسارات API التي تتولى المصادقة بنفسها "/((?!api|_next/static|_next/image|favicon.ico).*)", ], } -
9
استخدم Credentials provider لبريد/كلمة مرور
إذا احتجت تسجيل الدخول بالبريد الإلكتروني وكلمة المرور بدلًا من OAuth أو إلى جانبه، أضف Credentials provider إلى
auth.ts. قارن كلمة المرور بقيمة مُجزّأة من قاعدة البيانات — لا تخزن كلمات المرور كنص صريح أبدًا.typescript// auth.ts (إضافة Credentials provider) import Credentials from "next-auth/providers/credentials" import bcrypt from "bcryptjs" import { db } from "@/lib/db" // عميل قاعدة البيانات export const { handlers, signIn, signOut, auth } = NextAuth({ providers: [ Credentials({ credentials: { email: { label: "Email", type: "email" }, password: { label: "Password", type: "password" }, }, async authorize(credentials) { if (!credentials?.email || !credentials?.password) return null const user = await db.user.findUnique({ where: { email: credentials.email as string }, }) if (!user) return null const passwordMatch = await bcrypt.compare( credentials.password as string, user.passwordHash ) return passwordMatch ? user : null }, }), ], })
نصائح ومحاذير
- استخدم JWT sessions (الافتراضي) للـ APIs عديمة الحالة. انتقل إلى جلسات قاعدة البيانات فقط عندما تحتاج إلغاء الجلسات من جانب الخادم (مثل حظر الحسابات).
- وسّع كائن الجلسة بحقول مخصصة (معرف المستخدم، الدور) باستخدام `callbacks.session` و`callbacks.jwt` في `auth.ts` — هذا يتجنب رحلات إضافية إلى قاعدة البيانات مع كل طلب.
- في Google Cloud Console، أضف دائمًا عناوين callback الخاصة بالتطوير (`localhost`) والإنتاج إلى قائمة redirect URIs المصرّح بها قبل الإطلاق.
- لا تستدعِ `signIn()` أو `signOut()` من Client Component مباشرةً — لفّهما في Server Action أو استخدم رابط `/api/auth/signin` المدمج.
خاتمة
يختزل Auth.js v5 كود المصادقة المتكرر في ملف إعداد ومسار API واحد وتصدير middleware. بمجرد إعداده، إضافة مزودين جدد تصبح سطرًا واحدًا، وحماية مسارات جديدة تعني إضافة مسار إلى matcher في middleware. الجمع بين auth() من جانب الخادم وuseSession() من جانب العميل يغطي كل أنماط التصيير التي يتيحها App Router.