المستوى المطلوب: متوسط — تحتاج معرفة أساسية بـ Node.js و Express وكيف يشتغل الـ HTTP request/response. مش مطلوب خبرة سابقة بـ OAuth.
اعمل تسجيل دخول بحساب جوجل في Node.js بـ OAuth 2.0
في آخر هذا الدليل هيكون عندك زر "Sign in with Google" شغّال فعلاً: المستخدم يضغط، يوافق عند جوجل، ويرجع لموقعك وهو مسجّل دخول بإيميل موثّق. كله في أقل من 80 سطر Node.js، من غير ما تخزّن كلمة سر واحدة.
المشكلة باختصار
تخزين كلمات السر مسؤولية تقيلة: هاش، ملح، سياسة تعقيد، إعادة تعيين، وتسريبات محتملة. أغلب المستخدمين أصلاً عندهم حساب جوجل. تسجيل الدخول بجوجل بينقل عبء التحقق من الهوية لجوجل، فبتكسب أمان أعلى وتجربة أسرع. الافتراض هنا إن جمهورك بيستخدم Gmail أو Google Workspace فعلاً.
خلّينا نفهم OAuth بمثال بسيط الأول. تخيّل إنك داخل فندق. بدل ما تدّي عامل صف السيارات مفتاح بيتك كله، بتدّيله مفتاح مؤقت للعربية بس. هو يركن العربية، والمفتاح ده مبيفتحش بيتك ولا ينفع بعد ما تمشي. OAuth 2.0 بالظبط كده: موقعك ميشوفش باسورد المستخدم أبداً، بياخد بس "تصريح مؤقت" من جوجل يقول "الشخص ده فعلاً فلان، وإيميله كذا".
علمياً: OAuth 2.0 (المعرّف في RFC 6749) هو بروتوكول تفويض. الطريقة اللي بنستخدمها هنا اسمها Authorization Code Flow. موقعك بيوجّه المستخدم لجوجل، جوجل بترجّعه ومعاه كود تفويض قصير العمر، وموقعك بيبدّل الكود ده — من السيرفر للسيرفر — بـ access_token وid_token. الـ id_token هو اللي بيهمنا: توكن JWT فيه هوية المستخدم موقّعة من جوجل.
الخطوات كاملة
- سجّل تطبيقك في Google Cloud Console. افتح APIs & Services > Credentials، اختر Create Credentials > OAuth client ID، النوع Web application. هيديك
Client IDوClient Secret. النتيجة المتوقّعة: بيانات اعتماد تقدر تستخدمها في الكود. - ضيف الـ redirect URI المصرّح به. في نفس الشاشة، تحت Authorized redirect URIs، ضيف
http://localhost:3000/auth/google/callbackبالظبط. لو الرابط مختلف حرف واحد، جوجل هترفض الطلب بخطأredirect_uri_mismatch. - ركّب المكتبات.
npm install express google-auth-library express-session dotenvواحفظ بياناتك في ملف .env — ممنوع تحطها في الكود مباشرة:
GOOGLE_CLIENT_ID=xxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxxx
SESSION_SECRET=change_this_to_a_long_random_string- وجّه المستخدم لجوجل. لما يضغط الزر، ابنِ رابط تفويض فيه الـ
scopeاللي محتاجه بس (هنا: هوية وإيميل).
import express from "express";
import session from "express-session";
import { OAuth2Client } from "google-auth-library";
import "dotenv/config";
const app = express();
const REDIRECT = "http://localhost:3000/auth/google/callback";
const client = new OAuth2Client(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
REDIRECT
);
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { httpOnly: true, sameSite: "lax" }
}));
app.get("/auth/google", (req, res) => {
const url = client.generateAuthUrl({
access_type: "online",
scope: ["openid", "email", "profile"],
prompt: "select_account"
});
res.redirect(url);
});- استقبل الكود وبدّله بتوكن. جوجل بترجّع المستخدم على الـ callback ومعاه
?code=.... بدّل الكود بتوكن من السيرفر مباشرة. - تحقّق من الـ id_token. ده أهم سطر أمني في المقال كله. لا تفك التوكن وتصدّقه على طول — لازم تتأكد إن جوجل هي اللي وقّعته، وإنه صادر لتطبيقك انت بالذات.
app.get("/auth/google/callback", async (req, res) => {
try {
const { tokens } = await client.getToken(req.query.code);
// التحقق: التوقيع + الجمهور (audience) + انتهاء الصلاحية
const ticket = await client.verifyIdToken({
idToken: tokens.id_token,
audience: process.env.GOOGLE_CLIENT_ID
});
const payload = ticket.getPayload();
// payload فيه: sub, email, email_verified, name, picture
req.session.user = {
id: payload.sub, // معرّف ثابت للمستخدم عند جوجل
email: payload.email,
name: payload.name
};
res.redirect("/");
} catch (err) {
res.status(401).send("فشل تسجيل الدخول");
}
});
app.get("/", (req, res) => {
const u = req.session.user;
res.send(u ? `أهلاً ${u.name} (${u.email})` : `<a href="/auth/google">دخول بجوجل</a>`);
});
app.listen(3000, () => console.log("http://localhost:3000"));ركّز على حاجتين في الـ payload: sub هو المعرّف الثابت للمستخدم — استخدمه كمفتاح في قاعدة بياناتك، مش الإيميل، لأن الإيميل ممكن يتغيّر. وemail_verified لازم يكون true قبل ما تثق في الإيميل.
الـ trade-offs اللي لازم تعرفها
تسجيل الدخول بجوجل مش مجاني بالكامل من ناحية القرارات:
- بتكسب: صفر إدارة لكلمات السر، وتحقّق هوية أقوى. تبادل الكود بالتوكن بياخد عادةً بين 200 و 500 مللي ثانية (طلب شبكة واحد لجوجل)، وده بيحصل مرة عند الدخول بس.
- بتخسر: اعتماد على طرف خارجي. لو جوجل وقعت، مستخدمينك مش هيقدروا يدخلوا. وبتقيّد جمهورك على اللي عندهم حساب جوجل.
- الافتراض: الكود ده لتطبيق ويب بسيرفر. تطبيقات الموبايل والـ SPA ليها تدفق أنسب اسمه PKCE.
متى لا تستخدم هذه الطريقة
لا تستخدمها لو جمهورك مؤسسي وبيرفض حسابات جوجل الشخصية، أو لو محتاج تحكّم كامل في دورة حياة الحساب. كمان لو تطبيقك بدون سيرفر خلفي (Frontend بس)، الـ client_secret مينفعش يتحط في المتصفح — استخدم Authorization Code with PKCE بدل الطريقة دي. ولو محتاج تدعم إيميل/باسورد وجوجل مع بعض، فكّر في مزوّد هوية جاهز زي Auth0 أو Clerk بدل ما تبني كل حاجة بإيدك.
التحقق من أنه يعمل
- شغّل
node server.jsوافتحhttp://localhost:3000. - اضغط "دخول بجوجل" — المفروض يوجّهك لشاشة موافقة جوجل.
- وافق، وارجع للصفحة الرئيسية — المفروض تشوف اسمك وإيميلك.
- لو ظهر
redirect_uri_mismatch: راجع إن الرابط في الكود مطابق حرفياً للي في Console. - لو رجع 401: غالباً الـ
audienceفيverifyIdTokenمش مطابق للـClient ID.
الخطوة التالية
دلوقتي المستخدم في الجلسة بس مش في قاعدة بياناتك. الخطوة التالية: في الـ callback، بعد نجاح التحقق، اعمل upsert للمستخدم في جدول users بمفتاح payload.sub، وخزّن الإيميل والاسم. كده يبقى عندك سجل دائم تقدر تربط بيه بيانات المستخدم. جرّبها وشوف الصف بيتكوّن في أول تسجيل دخول بس، ومبيتكرّرش في الدخول اللي بعده.
المصادر
- توثيق جوجل الرسمي: Using OAuth 2.0 to Access Google APIs — developers.google.com/identity/protocols/oauth2
- توثيق جوجل: OpenID Connect (بنية الـ id_token والتحقق منه) — developers.google.com/identity/openid-connect/openid-connect
- مكتبة
google-auth-libraryعلى npm (التوثيق الرسمي لـ verifyIdToken و getToken). - RFC 6749: The OAuth 2.0 Authorization Framework — datatracker.ietf.org/doc/html/rfc6749