
یکی از رایج ترین روش احرازهویت که توی آموزش ها دربارش صحبت میشه اینه که یک Access Token و Refresh Token داشته باشیم (که اکثرا به اشتباه به این روش میگن JWT). تو این روش وقتی سرور بهمون بگه توکن دسترسی Access Token منقضی شده، باید در جواب یک درخواست جدید برای رفرش کردن توکن بفرستیم و بعد از گرفتن توکن جدید دوباره درخواست اول رو تکرار کنیم.
تابحال براتون سوال شده چرا باید اینکارو کنیم؟ اینکار غیر بهینه به نظر نمیرسه؟ چرا باید برای یه کار ساده سه تا درخواست بفرستیم؟ بهتر نبود همون سرور وقتی دید توکن تموم شده، خودش اتومات تمدیدش میکرد؟
سوال درستیه. واقعیت اینه که تو بیشتر سیستمهای کوچیک و مونولیت، این مدل احراز هویت (OAuth) داره مشکلی رو حل میکنن که اصلاً وجود نداره.
برای اینکه بفهمیم چرا این اتفاق میافته و چه موقعی از OAuth واقعاً لازمه، باید ببینیم اصلاً برای چی ساخته شد.
قبل از هر چیز، باید این سهتا مفهوم رو از هم جدا کنیم، چون خیلیا قاطیشون میکنن:
JWT (JSON Web Token) فقط یه فرمته برای ساخت و اعتبارسنجی توکن. خودش سیستم احراز هویت نیست. (RFC-7519)
OAuth 2.0 یک چارچوب برای Authorization ه. (RFC-6749)
OIDC (OpenID Connect) یه لایهی اضافه روی OAuth هست برای احراز هویت، (یعنی وقتی بخوایم بدونی کاربر واقعاً کیه). (Spec)
میتونی بدون OAuth از JWT استفاده کنی یا برعکس. OAuth فقط جریان کلی کار رو مشخص میکنه، ولی JWT شکل و امضای توکن رو.
OAuth برای یه نیاز خاص ساخته شد: اعطای مجوز بهصورت واگذار شده (delegated authorization).
اوایل وب، هر سایت خودش سیستم لاگین جدا داشت. باید برای هرکدوم جدا وارد میشدی چون دیتای کاربراش جدا بود. در نظر بگیرید که شرکتی مثل گوگل هستین و کلی سرویس دارین مثل Gmail، YouTube، Drive و Calendar. خب منطقی نیست برای هرکدوم جدا لاگین کنیم.
راه حلی که اینجا میتونیم داشته باشیم اینه که یک سرویس مسئله Authorization رو انجام بده و بقیه سرویس بتونن این مسئولیت رو به اون سرویس واگذار کنن. اینجا هر سرویس باید مستقل بمونه. مثلاً Gmail رمز عبورت رو نمیدونه و نمیتونه توکن رو تمدید کنه. فقط چک میکنه توکن هنوز معتبره یا نه.
اگه منقضی شده باشه، دیگه کاری ازش برنمیاد، چون فقط سرور احراز هویت (اون که توکن رو صادر کرده) اجازه داره تمدیدش کنه. اینجاست که OAuth میاد وسط! OAuth چهارچوبی رو مشخص میکنه و توضیح میده چطور این مسئله باید امن پیادهسازی بشه.
این جدایی دلیل اصلی امنیت سیستم OAuthه، ولی تو سیستمهای کوچیک باعث پیچیدگی بیخودی میشه.
تصور کن تو یه بانک بزرگی.
یه پیشخوان اصلی هست برای احراز هویت. میری کارت شناساییت رو نشون میدی، فرم پر میکنی، و یه کارت موقت بهت میدن که هویت شما رو توی بانک نشون میده. بعد میری باجههای دیگه با نشون دادن اون کارت کارهات رو انجام میدی.
اما نکته اینجاست: برای امنیت بیشتر این کارت فقط تا ده دقیقه قابل استفادهست! برای اینکه هر باجه مسئولیت احرازهویت شما رو نداشته باشه وقتی کارتت منقضی شده باشه فقط میتونه بگه: «ببخشید، کارتت منقضی شده، باید بری پیش میز اصلی تا برات تمدیدش کنن.»
این همون اتفاقیه که وقتی API بهت 401 یا 403 میده میافته.
حالا فرض کن اون بانک فقط یه اتاق کوچیک داره با یه باجه که خودش هم کارت میده هم کاراتو انجام میده.
خب دیگه چه نیازی داری بری و برگردی؟ میگی: «کارت من منقضی شده، لطفاً تمدیدش کن و کارمو انجام بده.»
و باجه هم همه رو با هم انجام میده.
این دقیقاً مثل برنامههای کوچیکه که فقط یه سرور دارن (Monollith). در این حالت، استفاده از OAuth فقط کار رو الکی سخت میکنه.
اگه کل بکاندت یه سرویسه (مثلاً یه سرور Express یا Django)، دیگه نیازی به اون جداسازی نیست.
تو این حالت، خیلی راحتتر که از session و cookie استفاده کنی:
وقتی کاربر لاگین میکنه، یه session ID تو سرور ذخیره میکنی (مثلاً تو Redis یا دیتابیس).
مرورگر یه کوکی سشن داره که خودش با هر درخواست ارسال میشه.
اگه سشن منقضی بشه، سرور خودش میتونه تمدیدش کنه و تو همون پاسخ دیتا رو برگردونه.
این همون روش سنتی وبه قبل از اینکه توکنها مد بشن. مدیریتش راحتتره، و کاملا امنه (اگه درست تنظیم بشه).
حتی اگه بخوای، حتی میتونی از JWT برای سشن استفاده کنی، ولی مهم اینه که کاربر درگیر نوسازی توکن نشه.
JWT فقط یه فرمت توکنه، نه یه سیستم لاگین.
OAuth 2.0 فقط جریان دسترسی دادن رو تعریف میکنه، نه شناسایی کاربر.
OIDC لایهی احراز هویت رو روی OAuth اضافه میکنه.
اگه سیستم کوچیک و یکپارچهای داری، از سشن و کوکی استفاده کن.
اگه چند سرویس جدا یا کلاینت شخص ثالث داری، OAuth + JWT گزینهی بهتریه.
تا وقتی واقعاً نیاز به احراز هویت توزیعشده نداری، سمت سادگی برو.