در بخش دوم، flowهای موجود در OAuth را بررسی کردیم.
در این بخش، Bearer Token را بررسی می کنیم و نحوه استفاده از آن را خواهیم دید. همچنین Refresh Token نیز از مواردی است که در این بخش بررسی می شود.
تا این مرحله از مطالب، client از طریق یک grant type موفق شد به یک access token دسترسی پیدا کند.
در رابطه با bearer token، یک توکن امنیتی می باشد که هر کسی آن را داشته باشد می تواند از آن استفاده کند و به resource دسترسی داشته باشد.
در OAuth flow و در مرحله سوم، client با استفاده از authorization server می تواند access token را از authorization server دریافت کند. موضوعیت صحبت ما در مورد موارد پنج و شش و نحوه استفاده از access token می باشد.
در RFC 6750، به سه راه حل در مورد استفاده از bearer token اشاره شده است. نکته ای که روی آن تاکید شده است این است که از بیشتر از یک روش برای ارسال توکن ها استفاده نکنیم.
روش authorization header، استفاده از هدر authorization همراه Bearer authentication scheme می باشد. بعد از Bearer با یک فاصله access token قرار می گیرد.
Authorization : Bearer cn389ncoiwuencr
راه حل پیشنهادی RFC، استفاده از این روش می باشد و resource serverهایی که از پروتکل OAuth استفاده می کنند، باید این موضوع را پشتیبانی کنند.
روش body parameter، ارسال توکن به عنوان یک پارامتر در بدنه درخواست است. اگر browser، استفاده از authorization header را پشتیبانی نکند می توانیم از این روش استفاده کنیم.
در این روش درخواست های ما باید حتما یک بخشی باشند. همچنین این روش در requestهای get نمی توانند مورد استفاده قرار بگیرند.
از آنجایی که این روش خیلی مرسوم نیست می تواند از سمت resource serverها پشتیبانی نشود.
روش URI parameter، ارسال پارامتر از طریق query string است. اگر به هر دلیلی authorization header یا قابلیت ارسال توکن در بدنه درخواست را نداشته باشیم، می توانیم از این روش استفاده کنیم. این روش به علت مشکلات امنیتی توصیه نمی شود.
در مرحله access token request، یک response در قالب json به دست client می رسد و آماده ارسال به resource server می شود.
{
"access_token" : ". . .",
"token_type" : ". . .",
"expires_in" : ". . . ",
"refresh_token" : ". . .",
}
در زمان ارسال به resource server، ممکن است access token درست باشد و resource مورد نظر به client برگردد. و یا ممکن است credential موجود نباشد یا access token معتبر نباشد و یا هر اتفاقی که منجر به رد شدن درخواست شود، اتفاق بیافتد. در این شرایط در response که به client برمی گردد، یک هدر به نام WWW-Authenticate وجود دارد که در آن پارامترهای مربوط به مشکلی که وجود داشته است مطرح می شود.
سه مدل خطا ممکن است اتفاق بیافتد.
خطای invalid_request، نشان می دهد که در request مشکلی وجود داشته است. برای مثال پارامتری را ارسال نکرده اید، پارامتری تکرار شده باشد، بیشتر از یک روش برای برای ارسال توکن انتخاب شده باشد و از این دسته از مشکلات، باعث می شود که خطای Bad Request - 400 به client برگردد.
خطای invalid_token، نشان می دهد که access token معتبر نیست. مشکلاتی مثل expire شدن، revoke یا ابطال شدن، باعث می شود خطای Unauthorized - 401 به client برگردد.
خطای insufficent_access، زمانی که scope مورد نظر در access token ذکر نشده باشد اتفاق می افتد و باعث می شود خطای Forbidden - 403 به client برگردد.
Refresh Token
یکی از مباحثی که در OAuth دیده شده است، جریان Refresh Token است. access token که به دست client می رسد، دارای یک زمان expire می باشد. refresh token در use caseهایی که می خواهیم client به token دسترسی طولانی تر داشته باشد و یا اصلاحا offline access داشته باشد، موضوعیت پیدا می کند. برای مثال زمانی که می خواهیم به یک build server دسترسی بدهیم تا امکان خواندن کدهای ما را از github داشته باشد و این امکان برای همیشه باشد.
در این flow، زمانی که با هر روشی authorization request انجام می شود و access token دریافت می شود، با توجه به scope تعیین شده برای آن client، یک refresh token نیز ممکن است از سمت authorization server به client برگردد.
زمانی که client از access token استفاده می کند و expire می شود یا هر اتفاقی دیگر می افتد، می تواند مجددا با استفاده از refresh token یک access token جدید دریافت کند و با توجه به flow مدنظر، refresh token جدید هم می تواند بگیرد.
درخواست refresh token و دریافت access token به این شکل انجام می شود.
در درخواست refresh token به token endpoint، پارامتر grant_type با مقدار refresh_token پر می شود و پارامتر refresh_token نیز با مقدار مشخص ارسال می شود و پاسخی مشابه به پاسخ دریافت access token دریافت می شود.
تنظیمات مربوط به clientهای authorization server به این صورت می باشد.
new Client { ClientId = "mvc", ClientSecrets = { new Secret("secret".Sha256()) }, AllowedGrantTypes = GrantTypes.Code, RedirectUris = { "https://localhost:5002/signin-oidc" }, AllowedScopes = new List<string> { "api1" }, // Refresh Token RefreshTokenUsage = TokenUsage.ReUse, RefreshTokenExpiration = TokenExpiration.Absolute, AbsoluteRefreshTokenLifetime = 300, AllowOfflineAccess = true, }
مقدار AllowOfflineAccess برابر true قرار گرفته است که refresh token grant type را برای این client فعال می کند. به صورت پیش فرض false می باشد.
مقدار AbsoluteRefreshTokenLifetime با مقدار پیش فرض 30 روز، زمان expire شدن یک refresh token می باشد.
مقدار RefreshTokenUsage، که می تواند OneTimeOnly یا ReUse باشد. در حالت ReUse چند بار و در حالت OneTimeOnly یکبار می توانیم از refresh token استفاده کنیم و بسته به تنظیمات می توانیم refresh token جدید دریافت کنیم.
مقدار RefreshTokenExpiration، که می تواند مقدار Absolute باشد که در زمان مشخص شده منقضی می شود و یا Sliding باشد به معنای اینکه اگر این refresh token برای مثال ده روز وقت دارد، به ازای هر بار استفاده ده روز دیگر تمدید می شود.
همچنین در client code request، در کنار scopeهای مورد نظر، offline_access هم باید ارسال شود. این scope مشخص می کند که client نیاز به refresh token هم دارد.
همانطور که در بخش قبل اشاره شد، clientها به دو بخش confidential و public تقسیم می شوند.
با توجه به امنیتی بودن refresh token، این موضوع بر روی confidential clientها موضوعیت پیدا می کند که بتواند آن را در یک جای امن ذخیره کند.
در تعریف پروتکل، با دو endpoint روبرو هستیم. Authorization Endpoint و Token Endpoint را در حال حاضر بررسی می کنیم.
در دو جریان Authorization Code و Implicit، برای دریافت authorization grant عملیات redirect را بر روی authorization endpoint انجام می دهیم. authorization endpoint یک پارامتر با نام response_type دارد که تا اینجا با مقادیر code و token در آن آشنا شدیم.
در token endpoint، جریان دریافت access token با استفاده از authorization grant یا refresh token توسط client انجام می شود. در token endpoint پارامتر grant_type را داریم که ممکن است با یکی از این مقادیر مقداردهی شود.
code, password, client_credentials, refresh_token
در implicit flow با token endpoint تعاملی نداریم. به این دلیل که زمانی که redirect انجام می شود، access token در redirection به آن برمی گردد.
در بخش بعدی به موضوعات پیرامون Authentication و OpenID Connect (OIDC) می پردازیم.