مجوزی که در این بخش به معرفی آن خواهیم پرداخت Authorization Code بوده که از رایج ترین Grant ها در پروتکل OAuth است. این Grant توسط برنامه های وب و بومی (native application) برای به دست آوردن Access Token به کار می رود. زمانی که یک کاربر، دسترسی برنامه به اطلاعات را تایید کند،Access Token صادر خواهد شد. شکل زیر روند Authorization Code را نشان می دهد. برای روشن شدن موضوع، شکل را بر اساس یک مثال شرح می دهیم.
- فرض کنید کاربری قصد دارد از طریق مرورگر در یک برنامه، لاگین کند که این برنامه، همان کلاینت است.
- برای لاگین، علاوه بر امکان لاگین موجود در خود برنامه ی کلاینت، گزینهیlogin with google نیز وجود داشته و کاربر امکان انتخاب دارد. کاربر با انتخاب این گزینه، به سرور اصلی OAuth هدایت شده و در حقیقت کلاینت درخواست خود را برای دسترسی به اطلاعات کاربر، به Authorization Server ارسال می کند. در این حالت پنجره جدیدی باز می شود تا کاربر در آن لاگین کند.
- سپس کاربر در Authorization Server لاگین کرده و درخواست کلاینت را تایید می کند.
- کاربر به همراه مقدار Authorization Code، مجدد به کلاینت هدایت می شود.
- بعد از این که کلاینت، Authorization Code را دریافت کرد، آن را در درخواست Access Token بهAuthorization Server می فرستد.
- در انتها Authorization Server، بر اساس Authorization Code که در درخواست کلاینت وجود دارد، درخواست کلاینت را تایید کرده و Access Token را به کلاینت می دهد.
در ادامه این بخش، به تشریح کامل روند Authorization Code خواهیم پرداخت.
دریافت اجازه ی کاربر
ابتدا کلاینت باید تصمیم بگیرد که مجوزهای مورد نظر خود را درخواست کند. برای این کار، کاربر را برای لاگین و دریافت مجوز به یک پنجره دیگر مرورگر ارسال می کند. در واقع برای شروع روند Authorization (برای مثال با کلیک بر روی دکمهی login with google)، کلاینت یک URL مانند زیر را ایجاد و آن را در یک پنجره ی دیگر مرورگر باز می کند و وقتی کاربر از این URL بازدید کند، Authorization Server از کاربر نهایی می پرسد که آیا می خواهد به درخواست این کلاینت مجوز دهد یا خیر.
https://authorization-server.com/auth
?response_type=code
&client_id=29352915982374239857
&redirect_uri=https://example-app.com/redirect
&scope=create+delete
&state=xcoiv98y2kd22vusuye3kch
هر یک از پارامترهای موجود در URL بالا به شرح زیر هستند:
- response_type: این پارامتر با مقدار Code، به سرور مجوز یا Authorization Server می گوید که کلاینت در حال شروع روند Authorization Code است.
- client_id: شناسه ی عمومی کلاینت است و هنگامی که برنامه نویس برای اولین بار کلاینت را ثبت کرد، به آن داده شده است. Authorization Server، کلاینت را با این شناسه تشخیص می دهد.
- redirect_uri: به Authorization Server می گوید که کاربر را پس از تایید درخواست، به آدرس موجود در این پارامتر، بازگرداند.
- scope: راهی برای محدود کردن دسترسی یک کلاینت به داده های کاربر است. Scope، به مشتریان API اجازه می دهد هنگام درخواست مجوز برای دسترسی به یک حساب، مجموعه ی خاصی از مجوزها را درخواست کنند و در حقیقت برای محدود کردن دسترسی کلاینت به حساب کاربر هستند. برای مثال، در یک کلاینت امکاناتی مانند خواندن، نوشتن، حذف و به روز رسانی برای یک کاربر، فراهم شده است. با استفاده از scopeها می توانیم به برنامه های کاربردی جهت انجام هر کدام از این کارها، دسترسی دهیم.
برخی از کلاینت ها فقط برای شناسایی کاربر از OAuth استفاده می کنند، بنابراین تنها به دسترسی به شناسه ی کاربر و اطلاعات اولیه ی پروفایل نیاز دارند. از طرفی دیگر ممکن است کلاینتی نیاز به دانستن اطلاعات حساس تر مانند روز تولد کاربر داشته باشد، یا نیاز به ارسال مطالب از طرف کاربر یا تغییر داده ها داشته باشد. Scope، روشی برای کنترل دسترسی و کمک به کاربر برای شناسایی مجوزهایی است که به کلاینت اعطا می کنند.
- state: این مورد برای جلوگیری از حمله های CSRF استفاده می شود. کلاینت، یک رشته ی تصادفی تولید می کند و آن را در درخواست قرار می دهد. پس از آن که کاربر، مجوز برنامه را صادر کرد، کلاینت باید بررسی کند که همان مقدار را برگردانده است یا خیر.
بازگشت به کلاینت
اگر کاربر درخواست را تایید کند، Authorization Server، مرورگر را بهredirect_uri که کلاینت آن را مشخص کرده، هدایت می کند و یک code و یک state را به رشته ی پرس و جو (query string) اضافه می کند.
برای مثال، کاربر دوباره به یک URL مانند زیر هدایت خواهد شد:
https://example-app.com/redirect
?code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3
&state=xcoiv98y2kd22vusuye3kch
مقدار state، همان مقداری خواهد بود که کلاینت در ابتدا در درخواست قرار داده است. انتظار داریم که کلاینت بررسی کند که state در حالت تغییر مسیر با state اولیه ی خود مطابقت دارد. این کار برای محافظت در برابر حمله ی CSRF و سایر حمله های مرتبط است.
مقدار code، همان Authorization Code تولید شده توسطAuthorization Server است. این کد نسبتا کوتاه بوده و تولید آن بسته به سرویس OAuth بین 1 تا 10 دقیقه زمان می برد.
مبادله ی Authorization Code برای یک Access Token
اکنون که کلاینت دارای کد مجوز یا همان Authorization Code است، می تواند از آن برای به دست آوردن Access Token استفاده کند. کلاینت با استفاده از پارامترهای زیر یک درخواست POST را به Token Endpoint سرویس (token endpoint یکی از درگاه های Authorization Server است که وظیفه ی برگرداندن Token را بر عهده دارد.) ارائه می دهد:
POST /oauth/token HTTP/1.1
Host: authorization-server.com
grant_type=authorization_code
&code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3
&redirect_uri=https://example-app.com/redirect
&client_id=29352915982374239857
&client_secret=xxxxxxxxxx
- grant_type = authorization_code: این پارامتر به token endpoint اشاره می کند که در این جا کلاینت از Grant نوع Authorization Code استفاده می کند.
- code: این پارامتر همان کد مجوز (authorization code) است که کلاینت قبلا از Authorization Server دریافت کرده بود.
- redirect_uri: همان URI تغییر مسیر که هنگام درخواست کد از آن استفاده شد. برخی از APIها به این پارامتر احتیاج ندارند، بنابراین باید مستندات API خاصی را که به آن دسترسی دارید، حتما بررسی کنید.
- client_id: همان شناسه ی عمومی کلاینت که در مرحله ی قبل نیز ارسال شده بود.
- client_secret: یک رمز و راز شناخته شده فقط برای کلاینت و Authorization Server است. این مقدار تضمین می کند که درخواست برای دریافت Access Token فقط از طریق کلاینت ساخته شده است، و نه از یک حمله کننده ی بالقوه که ممکن است Authorization Code را ردیابی کرده باشد.
Token endpoint، تمام پارامترهای موجود در درخواست را بررسی کرده و اطمینان حاصل می کند که کد هنوز منقضی نشده است و client_id و client_secret مطابقت دارند. به این معنی که client_secret مربوط به همان client_id است. اگر همه چیز درست باشد، یک Access Token ایجاد می کند و آن را در پاسخ باز می گرداند:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
"token_type":"bearer",
"expires_in":3600,
"refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
"scope":"create+delete"
}
تا این جا، جریان Authorization Code کامل شد. اکنون کلاینت دارای یک Access Token است که می تواند در هنگام درخواست API، از آن استفاده کند. در پاسخی که کلاینت از Authorization Server دریافت می کند، علاوه بر Access Token اطلاعات دیگری نیز وجود دارد مانند:
- token_type: نوع توکن را نشان می دهد.
- expires_in: تاریخ انقضای توکن است.
- refresh_token: همان طور که در بخش اصطلاحات توضیح داده شد، بعد از منقضی شدن توکن، برای دریافت توکن جدید استفاده می شود.
- scope: نشان دهنده ی محدودیت های دسترسی است.
چه زمانی باید از جریان Authorization Code استفاده کنیم؟
همان طور که قبلا گفته شد، جریان Authorization Code بهترین استفاده را در برنامه های وب و موبایل دارد. از آن جا که Authorization Code Grant یک مرحله ی اضافی جهت تبادل Authorization Code برای Access Token دارد، یک لایه ی امنیتی اضافی را ارائه می دهد که در نوع Implicit Grant وجود ندارد (در فصل های بعد این نوع را توضیح خواهیم داد). مرحله ی تبادل کد تضمین می کند که یک مهاجم قادر به رهگیری Access Token نیست، زیرا همیشه Access Token از طریق یک کانال امن بین کلاینت و Authorization Server ارسال می شود.
در مستندات اصلی OAuth 2.0، یک Grant با نام PKCE زیر مجموعه ی Grant Type آورده شده است. در حقیقت یک افزونه یا Extension است که جهت جلوگیری از حمله های خاص در روند Authorization Code، می توان از آن استفاده کرد. توصیه شده اگر از جریان Authorization Code در یک برنامه ی تلفن همراه یا هر نوع کلاینت دیگری که نمی تواند client secret را مخفی نگه دارد، استفاده می کنید، باید از افزونه PKCE استفاده کنید، که آن را در برابر حمله ها، محافظت کند. در مورد PKCE در بخش بعد بیشتر صحبت خواهیم کرد.