Cloudflare سرویس‌هایی ارائه می‌دهد که حدود 20% وب را پشتیبانی می‌کنند، اما این کار را تنها انجام نمی‌دهیم. توسعه‌دهندگان روی پلتفرم ما از مجموعه‌ای از ابزارها و سرویس‌های شرکت‌های دیگر هم استفاده می‌کنند. Cloudflare یک API غنی برای پلتفرم خود فراهم کرده که به توسعه‌دهندگان امکان ساخت اتوماسیون‌ها، CI/CD و ادغام‌هایی را می‌دهد که اجزای مختلف زیرساخت را به هم متصل می‌کنند. اوایل این ماه ما از قابلیت self-managed OAuth رونمایی کردیم تا مشتریان بتوانند راحت‌تر کلاینت‌های OAuth خود را برای دسترسی تفویض‌شده به Cloudflare API بسازند و مدیریت کنند. 🔐

Cloudflare در زمینه OAuth تازه‌کار نیست. اگر از Wrangler استفاده کرده‌اید یا ادغام‌هایی از شریکانی مثل PlanetScale را به کار برده‌اید، عملاً از OAuth استفاده کرده‌اید. اما تا امروز، OAuth شخص ثالث فقط از طریق تعداد کمی ادغام که به‌صورت دستی onboard شده بودند در دسترس بود و برای توسعه‌دهندگان به‌طور گسترده در دسترس نبود. در نتیجه، توسعه‌دهندگانی که می‌خواستند ادغام‌های خودشان را بسازند مجبور بودند به API tokens متکی باشند؛ توکن‌هایی که مدیریتشان سخت‌تر است و برای بسیاری از فلوهای delegated مناسب نیستند.

در سال گذشته ما تعداد فزاینده‌ای از شرکای اولیه را onboard کردیم و هم‌زمان مدل consent، revocation و امنیت پشت OAuth را بهبود دادیم. اما با رشد Developer Platform و افزایش تقاضا برای دسترسی تفویض‌شده از طرف ابزارهای agentic، مشخص شد که باز کردن OAuth برای همهٔ مشتریان برای موفقیت پلتفرم حیاتی است.

با self-managed OAuth، توسعه‌دهندگان می‌توانند یک فلو استاندارد OAuth ارائه دهند که در آن کاربران به‌صورت مستقیم دسترسی محدودی (scoped access) را اعطا می‌کنند؛ این کار ساخت ادغام‌های SaaS، پلتفرم‌های داخلی توسعه‌دهنده و ابزارهای agentic را آسان‌تر می‌کند و در عین حال به کاربران شفافیت بیشتر در consent، امکان revocation ساده‌تر و کنترل بهتر روی عملیات اپلیکیشن می‌دهد. ⚙️

Scaling the ecosystem securely — راه‌حل قبلی OAuth ما برای تعداد کمی شریک با مدیریت دقیق کفایت می‌کرد، اما متوجه شدیم که مدل مجوزها، تجربهٔ consent و روش‌های کاهش بردارهای احتمالی سوءاستفاده به اندازهٔ کافی بالغ نیستند. اوایل امسال تجربهٔ consent را به‌روزرسانی کردیم تا واضح‌تر نشان دهیم کدام اپلیکیشن درخواست دسترسی می‌کند و چه مجوزهایی دریافت خواهد کرد. همچنین امکان revocation را به داشبورد اضافه کردیم تا توسعه‌دهندگان بتوانند به‌راحتی کنترل کنند کدام اپلیکیشن‌ها به داده‌هایشان دسترسی دارند و مالکیت اپ‌ها را شفاف‌تر کردیم تا از OAuth phishing جلوگیری شود.

باز کردن self-managed OAuth برای همهٔ مشتریان نیازمند ارتقاءهای اساسی در موتور OAuth زیربنایی ما هم بود. این فرایند برنامه‌ریزی زیادی طلب کرد تا با کمترین اختلال برای کاربران انجام شود و هم‌زمان ثبات و امنیت داده را حفظ کند.

Planning the upgrade to our OAuth engine — سال‌ها قبل ما Hydra، یک OAuth engine متن‌باز، را برای تامین کار OAuth داخل Cloudflare مستقر کردیم. آن استقرار وقتی ترافیک کم بود خوب عمل کرد، اما با رشد پلتفرم و رواج agentic workflows مشخص شد که برای باز کردن قابلیت‌های جدید و بهبود عملکرد نیاز به ارتقاء اساسی داریم. در برنامه‌ریزی ارتقاء تصمیم گرفتیم دو ارتقاء کوچک‌تر متوالی انجام دهیم تا یک ارتقاء بزرگ: اول حرکت به آخرین نسخهٔ 1.X، بررسی هر تغییر رفتاری یا عملکردی، و سپس ارتقاء به 2.X.

در برنامه‌ریزی مشخص شد حتی ارتقاء به 1.X هم مشتریان را تحت تاثیر قرار می‌دهد چون دیتابیس Hydra نیاز به مهاجرت‌های گستردهٔ schema داشت که: ایجاد ایندکس‌ها به شکلی که قفل انحصاری روی جداول حیاتی بگیرد و مانع عملیات‌های مهم OAuth برای کاربران فعال شود؛ ستون‌هایی به جداول حیاتی اضافه کند و ستون‌های دیگر را به جداول جدید منتقل کند. همچنین یک نکتهٔ عجیب در نسخه‌ای از Hydra که استفاده می‌کردیم وجود داشت که SDK عملیات

SELECT *

انجام می‌داد و باعث مشکل در deserilization با تغییرات schema می‌شد.

برای جلوگیری از تاثیر منفی روی کاربران، ما SQL migrations را بازنویسی کردیم تا از امکاناتی مثل

CREATE INDEX CONCURRENTLY

استفاده کنند و یک نسخهٔ سفارشی از Hydra ساختیم که به‌جای

SELECT *

ستون‌های صریح را انتخاب می‌کرد.

با برنامه‌ریزی ارتقاء 1.X انجام‌شده، باید برنامه‌ای برای ارتقاء بزرگ‌تر 2.X طراحی می‌کردیم. سه گزینهٔ ممکن را شناسایی و مزایا و معایب هرکدام را سنجیدیم. ارتقاء در-place برای ما قابل‌اجرا نبود به‌خاطر حجم تغییرات schema که با یک major version همراه بود. تصمیم گرفتیم از استراتژی blue-green استفاده کنیم، اما کار فقط به تغییر یک سوییچ خلاصه نمی‌شد؛ فرایند مهاجرت ساعت‌ها طول می‌کشید و باید سیستم در آن بازه هم‌چنان درست کار می‌کرد.

گزینهٔ اول blue-green این بود که نوشتن به دیتابیس را غیرفعال کنیم تا هیچ مجوز جدیدی ثبت نشود. البته این مجوزها از بین نمی‌رفتند اما در زمان مهاجرت هیچ‌کس نمی‌توانست از اپ‌های OAuth موجود استفاده کند مگر اینکه قبلاً credential معتبر داشته باشد. مشکل بزرگ‌تر این بود که اگر کاربری می‌خواست در همان بازه دسترسی یک اپ را revoke کند، امکان‌پذیر نبود.

برای حل این مسائل، روشی پیدا کردیم که نوشتن به دیتابیس فعال بماند، هرچند برخی نوشت‌ها ممکن بود در لحظهٔ سوییچ به نسخهٔ green از دست بروند. اولین چیز کاهش تعداد نوشت‌ها برای توکن‌های جدید بود. یک اهرم عملیاتی کشیدیم: زمان انقضای توکن‌ها را به چند ساعت افزایش دادیم تا اپ‌هایی که پیش از ارتقاء توکن جدید گرفته‌اند بتوانند بدون نیاز به رفرش به کار خود ادامه دهند.

بعد از کاهش نوشت‌ها، باید راهی پیدا می‌کردیم تا هیچ revocation‌ای که کاربران در طول پنجرهٔ ارتقاء انجام می‌دهند از دست نرود. برای این کار یک سیستم صف ساختیم (با استفاده از Cloudflare Queues!) که بعد از هر رویداد revoke، رکوردی حاوی اطلاعات آن revocation را در صف می‌نویسد. بدین‌ترتیب می‌توانستیم پس از سوییچ دیتابیس به نسخهٔ green صف را خالی کنیم و همهٔ رویدادهای revocation را replay کنیم. این بخش حیاتی بود چون در غیر این صورت ممکن بود اپ‌هایی که کاربران revoke کرده‌اند به‌طور ناخواسته دسترسی‌شان بازگردد. 🔁

Executing the upgrade — Upgrading to 1.X: از منظر عملیاتی، اولین ارتقاء ما به آخرین نسخهٔ 1.X بدون هیچ مشکلی پیش رفت. مهاجرت‌های دیتابیس سفارشی سریع‌تر از انتظار اجرا شدند و هیچ تاثیری روی کاربران نداشتند. مجبور شدیم cutover سختی به نسخهٔ جدید انجام دهیم چون نسخهٔ قدیمی قادر به introspect توکن‌هایی که نسخهٔ جدید ایجاد کرده بود، نبود.

بعد از cutover، افزایش خطاهای مربوط به refresh token را مشاهده کردیم که قبلاً ندیده بودیم. علت این بود که نسخهٔ جدید رفتارهای سخت‌گیرانه‌تری در invalidation رفرش‌ها داشت؛ اگر یک refresh token دوباره استفاده می‌شد، Hydra کل زنجیرهٔ access و refresh token را invalid می‌کرد. این برای مشتری‌هایی مثل Wrangler و MCP مشکل‌ساز بود، چون هر دو حجم بالای درخواست دارند و یک reuse می‌توانست کل session را نابود کند.

برای کاهش این مشکل، رفتار refresh token coalescing را به Worker خود اضافه کردیم که ترافیک OAuth را به مقصد مناسب هدایت می‌کند. این اجازه داد تا به‌صورت موقت درخواست refresh token را قبل از رسیدن به Hydra cache کنیم، طوری که اگر retry تشخیص داده می‌شد بتوانیم درخواست را کوتاه‌مدت جواب دهیم بدون اینکه توکن‌ها invalid شوند. خوشبختانه نسخه‌های 2.X Hydra یک configurable “refresh token grace period” دارند که این مشکل را با اجازه دادن به retry برای یک بازهٔ زمانی بدون invalid کردن کل زنجیره حل می‌کند.

Upgrading to 2.X: از آنجا که چند ساعت اختلال سنگین برای کاربران قابل‌پذیرش نبود، استراتژی blue-green را آماده کردیم. در سطح بالا همه‌چیز ساده به‌نظر می‌رسد: مهاجرت‌ها روی یک کپی از دیتابیس تولید اجرا شوند و سپس بعد از تکمیل با نسخهٔ جدید Hydra cutover انجام شود. اما واقعیت پیچیده‌تر بود و اجزای زیادی درگیر بودند: فعال کردن revocation replay capture queue؛ کپی و restore دیتابیس به هدف جدید؛ پاک‌سازی هدفمند داده‌ها — چون داده‌های موجود بعضاً با محدودیت‌های جدید نسخهٔ تازه مغایرت داشتند و ممکن بود مهاجرت‌ها را ناکام بگذارند؛ انجام cutoverها برای سرویس Hydra همراه با دو سیستم داخلی حیاتی دیگر هم‌زمان تا از بروز خطا جلوگیری شود؛ و پایش و اعتبارسنجی پس از cutover.

یک پنجرهٔ ارتقاء انتخاب کردیم که Hydra کمترین نرخ درخواست بر ثانیه را داشته باشد تا تعداد نوشت‌های توکن از دست رفته کم شود. به‌جز تنظیمات timeout، مهاجرت‌های تولید روی دیتابیس جدید خوب اجرا شدند: زمان خالص اجرا در تولید تقریباً سه ساعت بود. پس از اتمام مهاجرت‌ها، با دقت نسخهٔ جدید سرویس Hydra را راه‌اندازی کردیم و دو تنظیم سیستمی اضافه را هم بالا آوردیم تا سیستم‌هایمان از SDK جدید استفاده کنند.

کوتاه پس از سوییچ ترافیک، مشاهده کردیم که یک job پاک‌سازی داده در سرویس authorization ما (که به Hydra consent session API وابسته است) بیش‌ازحد تهاجمی در پاک‌سازی داده‌های سیاست OAuth عمل می‌کند. بعد از بررسی متوجه شدیم که یکی از مهاجرت‌های Hydra حالت برخی sessionهای معتبر OAuth را خراب کرده بود و در نتیجه مهاجرت آن‌ها را نامعتبر علامت‌گذاری کرده بود. این فساد داده باعث اختلاف بین Hydra و سرویس authorization ما شد و به افزایش 403ها منجر گشت. برای کاهش این مشکل ما داده‌ها را بازیابی کردیم و کار روی بهبود رفتارهای authorization OAuth را برای کاهش وابستگی به دادهٔ ایستا (static policy data) شروع کردیم.

فراتر از مسئلهٔ پاک‌سازی داده، چند اصلاح کوچک دیگر که ناشی از رفتارهای خاص کلاینت‌ها بودند را سریع اعمال کردیم. با تکمیل ارتقاء نسخهٔ Hydra، ترافیک OAuth پایدار ماند و عملکرد و قابلیت اطمینان سیستم برای مشتریان بهبود یافت. این ارتقاء همچنین production را روی همان بنیانی قرار داد که APIهای جدیدتر OAuth ما پیش‌تر در staging آن‌ها را اعتبارسنجی کرده بودند و راه را برای انتشار self-managed OAuth در June 3 باز کرد. 🚦

Performance improvements — بعد از تکمیل یک ارتقاء بزرگ مثل این، بررسی متریک‌های کلی دربارهٔ تاثیرات همیشه مفید و روشنگر است. ما در طول مهاجرت‌های دیتابیس متریک‌های اضافی جمع‌آوری کردیم و تغییرات قابل توجهی در عملکرد مشاهده کردیم که ادامهٔ جزئیات آن به‌طور فنی می‌تواند به تیم‌های SRE و DevOps کمک کند تا نتایج را بهتر تفسیر و برای موارد مشابه برنامه‌ریزی کنند. 📈