اگه به فکر ساختن یه پلتفرم یا یه ادغام بین دو پلتفرم هستی، به زودی با پروتکل OAuth 2.0 روبهرو میشی. تو این مقاله، نکات مهم و مثالهای کاربردی در مورد این پروتکل رو میارم و راهنمایی میکنم که چطور میتونی خودت هم ازش استفاده کنی.
تو این بلاگ بیشتر تمرکزم روی Authorization Code Flow هست، چون رایجترین روشی هست که تو OAuth 2.0 استفاده میشه و احتمالاً توی کارهات بیشتر باهاش سروکار داری.
بیایم چند تا مثال بزنیم:
توی این موارد، اپلیکیشن کاربر رو به صفحه توییتر یا تقویم گوگل هدایت میکنه تا اجازه دسترسی بگیره. وقتی کاربر مجوز رو داد، اپلیکیشن میتونه کارهایی مثل تنظیم خودکار وظایف و زمانبندیها توی تقویم گوگل انجام بده.
همونطور که حدس زدی، این جریان کامل با استفاده از پروتکل OAuth 2.0 مدیریت میشه!
خب، بذار یه مثال ساده بزنم. فرض کن که میخوای به دوستت اجازه بدی از ماشینت استفاده کنه، اما نمیخوای بهش کلید اصلی ماشین رو بدی، چون کلید اصلی دسترسی کامل به همه چیز داره: میتونه در ماشین رو باز کنه، صندوقعقب رو باز کنه، و حتی اگه بخواد ماشین رو هم بفروشه! تو بهش یه کارت دسترسی موقت میدی که فقط اجازه میده ماشین رو روشن کنه و رانندگی کنه، اما هیچ کار دیگهای نتونه بکنه. حالا OAuth 2.0 هم دقیقاً همین کار رو برای دسترسی به اطلاعات کاربر انجام میده.
OAuth 2.0 یه پروتکل (یا بهتره بگیم یه چارچوب) هست که به اپلیکیشنها اجازه میده بدون اینکه رمز عبور کاربر رو دریافت کنن، به سرویسهای دیگه دسترسی پیدا کنن. به جای اینکه اپلیکیشنها به طور مستقیم به اطلاعات حساس کاربر دسترسی داشته باشن، OAuth 2.0 یه توکن دسترسی (Access Token) بهشون میده که فقط دسترسی محدودی داره؛ دقیقاً مثل همون کارت موقتی که به دوستت دادی.
نکته جالب اینجاست که این پروتکل وقتی به کار میاد که بخوای به یه اپلیکیشن یا سرویس اجازه بدی به حسابهای کاربری یا اطلاعاتت در سرویسهای دیگه مثل Google، Twitter یا Facebook دسترسی داشته باشه. مثلاً وقتی میخوای با حساب Google وارد یه سایت بشی و سایت ازت میخواد که به پروفایلت دسترسی پیدا کنه، پشت صحنه داره از OAuth 2.0 استفاده میکنه. به جای اینکه رمز Gmailت رو به اون سایت بدی (که خیلی خطرناکه!)، Google یه توکن موقت به اون سایت میده که فقط به همون چیزهایی که اجازه دادی دسترسی داشته باشه، مثلاً فقط به پروفایل یا ایمیلت.
حالا شاید بپرسی "خب، قبل از OAuth چی کار میکردیم؟" خب، تو روشهای قدیمی، اگه یه اپلیکیشن میخواست به سرویس دیگهای متصل بشه، باید رمز عبور کاربر رو ازش میگرفت. مشکل اینجا بود که رمز عبور یه چیز خیلی حساس و شخصیه؛ اگه اون اپلیکیشن امن نبود یا اطلاعاتش لو میرفت، کل حساب کاربری کاربر به خطر میافتاد.
علاوه بر این، یه دردسر دیگه هم داشت: کاربر باید برای هر سرویس یه رمز جدید میساخت و اگه میخواست دسترسی یه اپلیکیشن رو قطع کنه، باید رمز رو تغییر میداد، که این موضوع خودش کلی دردسر و سردرگمی ایجاد میکرد.
اما با OAuth 2.0، همه این مشکلات کنار رفتن. حالا کاربر فقط مجوز خاصی به اپلیکیشن میده که دسترسی موقتی و محدود داره، و هر وقت بخواد میتونه اون مجوز رو قطع کنه، بدون اینکه نیاز به تغییر رمز باشه. این باعث میشه که امنیت کاربر به طور چشمگیری افزایش پیدا کنه.
توی حالت عادی، یه اپلیکیشن برای دسترسی به یه سرویس باید از اطلاعات لاگین کاربر (مثل رمز عبور) استفاده کنه. اما این روش کلی مشکل داره، مثل:
OAuth این مشکلات رو حل میکنه. با OAuth، اپلیکیشن بدون اینکه به رمز کاربر نیاز داشته باشه، میتونه به سرویس دسترسی پیدا کنه. چطوری؟ با استفاده از "توکن دسترسی". توکن یه کلید موقته که اپلیکیشن فقط به اطلاعات خاصی که کاربر بهش اجازه داده، دسترسی داره و بعد از یه مدت هم منقضی میشه. این توکن رو سرویس مورد نظر (مثل Google یا Twitter) بعد از اینکه کاربر اجازه داد، برای اپلیکیشن صادر میکنه. به این شکل، امنیت بیشتره و نیازی به درگیر شدن با رمز عبور نیست.
خب حالا که متوجه شدی چرا به OAuth نیاز داریم، بیایم بریم سراغ جریان OAuth 2.0. قراره توی این بخش قدمبهقدم با مراحل این پروتکل آشنا بشیم و با اصطلاحات خاصش آشنا بشیم.
حالا بیایم ببینیم چه افرادی یا سیستمهایی تو این جریان نقش دارن:
برای اینکه یه جمعبندی داشته باشیم، میتونیم بگیم که:
خب حالا بریم سراغ جریان اصلی پروتکل OAuth 2.0، مخصوصاً Authorization Code Flow که بیشتر مواقع ازش استفاده میشه. توی این جریان، کلاینت (اپلیکیشن) به کمک مرورگر کاربر و ریدایرکتهایی که از سمت سرور مجوز (Authorization Server) میشه، هم توکن دسترسی (Access Token) و هم توکن بازنشانی (Refresh Token) رو میگیره. حالا بیایم قدمبهقدم جلو بریم:
در این مرحله، اپلیکیشن (کلاینت) کاربر رو به سمت سرور مجوز هدایت میکنه. این هدایت شامل یه سری اطلاعات مهمه مثل شناسه کلاینت، اطلاعاتی که اپلیکیشن نیاز داره، آدرسی که قراره بعد از تایید مجوز بهش برگرده، و یه سری داده محلی برای پیگیری.
حالا کاربر به یه صفحه منتقل میشه که توش توضیح داده شده اپلیکیشن میخواد به اطلاعاتش دسترسی پیدا کنه. کاربر اینجا میتونه تصمیم بگیره که آیا اجازه بده یا نه.
در اینجا، کاربر وارد سرور مجوز میشه (با وارد کردن اطلاعات حساب کاربری) و تصمیم میگیره که آیا به اپلیکیشن اجازه دسترسی بده یا نه.
اگه کاربر به اپلیکیشن مجوز بده، سرور مجوز کاربر رو به آدرسی که اپلیکیشن تعیین کرده بود برمیگردونه. همراه با این برگشت، یه کد مجوز (Authorization Code) و همون دادههای محلی مرحله اول هم فرستاده میشن.
اپلیکیشن (کلاینت) این کد مجوز رو به سرور مجوز میفرسته و هویتش رو تایید میکنه (مثلاً با استفاده از کلید محرمانهای که قبلاً داشت). در این مرحله، اپلیکیشن از سرور مجوز درخواست میکنه که این کد رو با یه توکن دسترسی عوض کنه.
اگه همه چیز درست باشه و سرور مجوز مطمئن بشه که همه مراحل قبلی به درستی انجام شدن، به اپلیکیشن یه توکن دسترسی میده. این توکن به اپلیکیشن اجازه میده تا به دادههای مشخصی که کاربر مجوز داده بود دسترسی پیدا کنه. ممکنه سرور مجوز یه توکن بازنشانی هم بده که اپلیکیشن بعداً بتونه ازش برای گرفتن توکنهای دسترسی جدید استفاده کنه.
این جریان ساده و مشخص به اپلیکیشن کمک میکنه بدون نیاز به دسترسی مستقیم به رمز عبور کاربر، مجوزهای لازم رو بگیره و به سرویسهای دیگه متصل بشه.
OAuth 2.0 میتونه یه کم پیچیده به نظر برسه، مخصوصاً اگه اولین بارته که داری ازش استفاده میکنی. برای اینکه بهتر متوجهش بشی، بیاین این مفهوم رو به چند بخش ساده تقسیم کنیم و یه مدل ذهنی براش بسازیم.
اول از همه، بیاین چندتا تعریف رو مرور کنیم:
حالا که با این مفاهیم آشنا شدیم، بریم سراغ اینکه هر مرحله از این فرآیند چطوری اتفاق میافته و از دید کاربر چه مسیری طی میشه.
بیاین مرحله به مرحله و به زبون ساده به فرآیند OAuth 2.0 نگاه کنیم:
(A) هدایت کاربر از مرورگر به سرویس: کاربر روی یه دکمه توی مرورگر کلیک میکنه و به سرویس مورد نظر (مثل گوگل، فیسبوک یا هر سرویس دیگهای) هدایت میشه، جایی که باید اجازه بده اپلیکیشن به اون سرویس دسترسی داشته باشه.
(B) بازگشت کاربر از سرویس به مرورگر: بعد از اینکه کاربر دسترسی رو تایید کرد، به مرورگر برمیگرده، اما این بار با یه کد مخصوص که بهش "authorization code" میگیم.
(C) تبادل کد با توکن: حالا اون کد رو از مرورگر میفرستیم به سرور اپلیکیشن تا با سرویس مورد نظر عوض بشه. بعد از این تبادل، باید یه توکن دسترسی (access_token) و گاهی هم یه توکن تازهسازی (refresh_token) بگیریم.
(D) استفاده از توکن دسترسی برای درخواستها: با داشتن access_token، میتونیم از طرف کاربر به سرویس مورد نظر درخواستهایی بفرستیم. اگه access_token منقضی بشه، با استفاده از refresh_token میتونیم یه توکن جدید بگیریم و به کارمون ادامه بدیم.
حالا بریم عمیقتر بشیم توی هر مرحله:
(A) هدایت کاربر از مرورگر به سرویس: برای این کار، فقط کافیه کاربر رو با استفاده از کدی مثل window.location.assign() به سمت سرویس هدایت کنی. معمولاً توی این مرحله باید یه پارامتر به اسم state ایجاد کنی که توی حافظه محلی (local storage) ذخیره بشه و همراه با ریدایرکت ارسال بشه. شاید لازم باشه client_id رو هم بفرستی.
(B) بازگشت کاربر از سرویس به مرورگر: اینجا فقط باید مقدار state که از سرویس برگشته رو با مقدار ذخیره شده توی مرحله قبل مقایسه کنی. اگه این دوتا مقدار با هم همخوانی داشتن، میتونیم بریم سراغ مرحله بعد.
(C) تبادل کد با توکن: توی این مرحله، کدی که از مرحله قبل گرفتیم رو به سرور اپلیکیشن میفرستیم تا با سرویس تبادل بشه و توکنهای access_token و refresh_token رو بگیریم.
(D) استفاده از توکن دسترسی برای درخواستها: حالا که access_token رو داریم، میتونیم از طرف کاربر به سرویس درخواست بفرستیم. باید حواسمون باشه که هر وقت این توکن منقضی شد، با استفاده از refresh_token یه توکن جدید بگیریم و همچنان درخواستهامون رو ادامه بدیم.
و تمام! حالا آمادهایم تا OAuth 2.0 رو پیادهسازی کنیم.
یه مقاله کامل درباره پیادهسازی OAuth بدون یه مثال واقعی ناقصه! تو این بخش میخوام بهت نشون بدم چطور میتونی با استفاده از OAuth 2.0 و Authorization Code Flow به Google API متصل بشی و احراز هویت کنی. این روش خیلی کاربرد داره و توی پروژههایی مثل Infisical هم ازش استفاده شده.
با استفاده از Google API، اپلیکیشن وب تو میتونه به سرویسهای گوگل و اطلاعات کاربرها دسترسی پیدا کنه. توی یه نگاه کلی، باید اول یه اپلیکیشن OAuth توی پلتفرم Google Cloud (GCP) تنظیم کنیم و بعدش جریان OAuth 2.0 رو توی اپلیکیشن خودمون پیادهسازی کنیم تا بتونیم به سرویسهای گوگل وصل بشیم.
بزن بریم ببینیم چطوریه!
برای ایجاد اپلیکیشن OAuth، باید یه فرم رو پر کنی. توی بخش Authorized redirect URIs، یه URL مثل این اضافه کن: https://your-domain.com/integrations/google/oauth2/callback. این همون URLایه که وقتی کاربر اجازه دسترسی به حساب گوگلش رو به اپلیکیشن داد، گوگل اونو به این آدرس برمیگردونه.
بعدش باید Client ID و Client Secret مربوط به اپلیکیشن Google OAuth2 رو دریافت کنی؛ اینها رو نگه دار چون بعداً بهشون نیاز خواهی داشت.
حالا باید اپلیکیشن وب تو رو طوری تنظیم کنیم که بتونه با GCP تعامل داشته باشه:
توی فرانتاند اپلیکیشن وب، یه دکمه درست کن که وقتی کاربر روی اون کلیک کرد، جریان OAuth 2.0 رو شروع کنه. این دکمه باید کاربر رو به گوگل هدایت کنه تا بتونه وارد بشه و دسترسی اپلیکیشن رو به حساب گوگلش تأیید کنه. کد مربوط به هندلر دکمه به این شکل هست:
// client_id که از GCP گرفتی
const client_id = ""
// ساخت یه توکن CSRF و ذخیره کردنش به صورت محلی
const state = crypto.randomBytes(16).toString("hex");
localStorage.setItem("latestCSRFToken", state);
// هدایت کاربر به گوگل
const link = `https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/cloud-platform&response_type=code&access_type=offline&state=${state}&redirect_uri=${window.location.origin}/integrations/google/oauth2/callback&client_id=${client_id}`;
window.location.assign(link);
اینجا، یه توکن CSRF تولید میکنیم و اونو توی حافظه محلی (local storage) ذخیره میکنیم و به عنوان پارامتر state همراه با درخواست به GCP میفرستیم. این کار برای جلوگیری از حملات CSRF هست، که توضیح بیشترش خارج از بحث این مقالهست.
یادت باشه که باید مقدار redirect_uri رو با همون URLای که تو مرحله دوم توی GCP ثبت کردی جایگزین کنی. وقتی کاربر روی دکمه کلیک میکنه، باید به گوگل هدایت بشه.
بعد از اینکه کاربر وارد حساب گوگلش شد و به اپلیکیشن اجازه دسترسی داد، گوگل اونو به redirect_uri که قبلاً ثبت کردی برمیگردونه. حالا نیاز داری یه صفحه بسازی که بتونه ادامه جریان OAuth 2.0 رو مدیریت کنه. وقتی کاربر برمیگرده، این redirect_uri شامل یه پارامتر code و state هست. باید این پارامترها رو از URL استخراج کنی و مطمئن بشی که مقدار state همون مقداریه که تو مرحله قبل به عنوان CSRF توکن تو حافظه محلی ذخیره کردی. اگه همه چیز اوکی بود، میتونی کد رو به سرور اپلیکیشن بفرستی تا تبادل کد-توکن انجام بشه.
مثال کد:
const { code, state } = queryString.parse(router.asPath.split("?")[1]);
// اعتبارسنجی پارامتر state
if (state !== localStorage.getItem("latestCSRFToken")) {
localStorage.removeItem("latestCSRFToken");
// ارسال کد به سرور برای تبادل توکن
const res = await axios.post("/api/oauth-token", {
code
});
}
حالا توی بکاند اپلیکیشنت باید این کد رو به API گوگل بفرستی و توکنهای access_token و refresh_token رو بگیری:
const res = await axios.post(
"https://oauth2.googleapis.com/token",
new URLSearchParams({
grant_type: "authorization_code",
code: code,
client_id: process.env.GCP_CLIENT_ID,
client_secret: process.env.GCP_CLIENT_SECRET,
redirect_uri: `your-domain/integrations/gcp-secret-manager/oauth2/callback`,
} as any)
);
const access_token = res.data.access_token; // توکنی که برای دسترسی به Google API استفاده میکنیم
const refresh_token = res.data.refresh_token; // توکنی که برای تازهسازی access_token استفاده میکنیم
const expires_in = res.data.expires_in; // زمانی که توکن منقضی میشه و باید تازه بشه
حالا که access_token رو داری، میتونی از طرف کاربر به Google API درخواست بفرستی. هر وقت access_token منقضی شد، با استفاده از refresh_token یه توکن جدید دریافت کن تا به کاربر دسترسی داشته باشی.
در مرحله ۶، شاید متوجه شده باشی که GCP دو فیلد اضافی دیگه هم برمیگردونه که ما اونا رو به متغیرهای refresh_token و expires_in متصل میکنیم. چون access_token یه توکن کوتاهمدت برای دسترسی به Google API هست، فیلد expires_in به ما میگه که این توکن چه زمانی منقضی میشه. وقتی فهمیدیم که access_token منقضی شده، میتونیم یه درخواست API ویژه با استفاده از refresh_token به endpoint مخصوص توکن بفرستیم تا یه access_token جدید بگیریم و به دسترسی به Google API ادامه بدیم.
مثال کد:
const res = await standardRequest.post(
"https://oauth2.googleapis.com/token",
new URLSearchParams({
client_id: process.env.GCP_CLIENT_ID,
client_secret: process.env.GCP_CLIENT_SECRET,
refresh_token: refreshToken,
grant_type: "refresh_token",
} as any)
);
const accessToken = res.data.access_token;
const expiresIn = res.data.expires_in;
پیادهسازی درست OAuth 2.0 برای امنیت اپلیکیشن و کاربرهات خیلی مهمه. اینجا چندتا نکته عملی آوردم که باید بهشون توجه کنی:
OAuth 2.0 یه پروتکل برای دادن مجوز دسترسی به اپلیکیشنهاست بدون اینکه نیاز باشه رمز عبور کاربر رو بگیری. به این ترتیب، امنیت کاربر بالا میره و اپلیکیشنها دسترسی موقتی و محدود به اطلاعات کاربر دارن. این پروتکل برای اتصال اپلیکیشنها به سرویسهای بزرگی مثل گوگل و فیسبوک استفاده میشه.
توی این روش، اپلیکیشن کاربر رو به سرویس مورد نظر هدایت میکنه تا مجوز بگیره. بعد از اینکه کاربر اجازه داد، سرویس یه "کد مجوز" میفرسته که اپلیکیشن میتونه اون کد رو با یه "توکن دسترسی" عوض کنه. این توکن به اپلیکیشن اجازه میده به اطلاعات مشخصی دسترسی داشته باشه.
در روشهای قدیمی، اپلیکیشنها برای دسترسی به اطلاعات کاربر باید رمز عبور کاربر رو دریافت میکردن. این روش هم ناامن بود و هم مدیریت دسترسیها خیلی سخت بود. ولی توی OAuth 2.0، به جای دریافت رمز عبور، یه توکن موقت و محدود به اپلیکیشن داده میشه که امنیت خیلی بیشتری داره.
هر وقت اپلیکیشنی بسازی که نیاز داره به اطلاعات کاربر تو سرویسهای دیگه دسترسی داشته باشه، مثلاً وقتی میخوای یه اپ بسازی که بتونه با تقویم گوگل یا اکانت توییتر کاربر تعامل داشته باشه، OAuth 2.0 بهترین گزینه هست.
پیادهسازی درست OAuth 2.0 نیاز به دقت زیادی داره، مثل مدیریت درست توکنها و جلوگیری از حملات امنیتی مثل CSRF. همچنین باید مطمئن بشی که Client ID و Client Secret به صورت امن نگهداری میشن و توی کد هاردکد نمیشن.
OAuth 2.0 بهطور کلی خیلی امنه، چون نیازی به ارسال یا نگهداری رمز عبور نداری. اما اگه درست پیادهسازی نشه، میتونه مشکلات امنیتی ایجاد کنه. نکته مهم اینه که همیشه از روشهای ایمن برای نگهداری توکنها و اعتبارسنجی درخواستها استفاده کنی.
Refresh Token یه توکنیه که بعد از منقضی شدن Access Token، ازش استفاده میکنی تا یه توکن جدید بگیری. با استفاده از Refresh Token میتونی بدون اینکه کاربر دوباره لاگین کنه، دسترسی به اطلاعات رو ادامه بدی.
بله، OAuth 2.0 برای اپلیکیشنهای موبایل هم به خوبی کار میکنه. میتونی از روشهایی مثل Authorization Code Flow با PKCE استفاده کنی که مخصوص اپهای موبایله و امنیت بیشتری داره.
Access Token توکنیه که اپلیکیشن ازش برای دسترسی به اطلاعات کاربر استفاده میکنه. این توکن معمولاً عمر کوتاهی داره. اما Refresh Token توکنیه که وقتی Access Token منقضی میشه، ازش برای گرفتن یه Access Token جدید استفاده میکنی.
برای جلوگیری از حملات CSRF، توی مرحله اول OAuth 2.0 باید یه پارامتر به اسم state ایجاد کنی و اون رو به سرور مجوز بفرستی. وقتی کاربر برمیگرده، باید مقدار state که برمیگرده رو با مقداری که اول ذخیره کردی مقایسه کنی.
OAuth 2.0 یه جریان خیلی مهم تو اکثر اپلیکیشنهای وب هست که امکان احراز هویت با سرویسهای دیگه رو فراهم میکنه. حالا که این جریان رو درک کردی و یه مدل ذهنی ازش ساختی، و یه مثال کاربردی از پیادهسازی با گوگل رو هم دیدی، امیدوارم الان برای پیادهسازی OAuth 2.0 توی اپلیکیشنهای خودت اعتماد به نفس لازم رو پیدا کرده باشی!😉
دوره الفبای برنامه نویسی با هدف انتخاب زبان برنامه نویسی مناسب برای شما و پاسخگویی به سوالات متداول در شروع یادگیری موقتا رایگان شد: