Web Locks API पाँच खुले टैब को एक साथ auth server पर refresh-token calls की बौछार करने से रोक सकता है, जिससे यूज़र्स को अचानक होने वाले logouts से बचाया जा सकता है। टैब के बीच रिफ्रेश को कोऑर्डिनेट करके, एक सिंगल रिक्वेस्ट उस भीड़ की जगह ले लेती है जो आमतौर पर Refresh Token Rotation के इस्तेमाल के दौरान सेशन-किल (session-kill) को ट्रिगर करती है।

मल्टी-टैब सेशन में छिपा हुआ ओवरलोड

एक सामान्य single-page app एक Axios interceptor जोड़ता है जो 401 response पर नज़र रखता है, एक Boolean isRefreshing flag को बदलता है, और तब तक सभी आउटगोइंग रिक्वेस्ट को कतार (queue) में रखता है जब तक कि नया JWT न आ जाए। एक टैब में टेस्ट करने पर, यह फ्लो बिना किसी समस्या के काम करता है।

उसी ऐप को पाँच टैब में खोलें, access token को एक्सपायर होने दें, और सभी पाँचों टैब एक ही मिलीसेकंड में 401 को नोटिस करेंगे। हर टैब को लगता है कि उसे रिफ्रेश करना चाहिए, इसलिए पाँचों एक जैसी refresh-token रिक्वेस्ट auth server की ओर दौड़ती हैं। Refresh Token Rotation के साथ—एक सुरक्षा उपाय जो नया टोकन जारी होते ही पिछले refresh token को अमान्य कर देता है—सर्वर दूसरी रिक्वेस्ट को replay attack के रूप में देखता है, सेशन को कॉम्प्रोमाइज्ड (compromised) मार्क करता है, और उसे रिवोक (revoke) कर देता है। यूज़र तुरंत हर टैब से लॉग आउट हो जाता है।

इसका मूल कारण JavaScript का isolation model है। isRefreshing जैसा वेरिएबल केवल उसी टैब में रहता है जिसने इसे सेट किया है; अन्य टैबों को यह जानने का कोई तरीका नहीं है कि रिफ्रेश पहले से ही चल रहा है। इसका परिणाम एक क्लासिक concurrency problem है, लेकिन यहाँ "processes" के बजाय ब्राउज़र टैब काम कर रहे हैं।

क्रॉस-टैब लॉक ही सही टूल क्यों है

हमें एक ऐसे तरीके की आवश्यकता है जिससे टैब एक साझा संसाधन (shared resource)—इस मामले में, नया JWT—के बारे में एक-दूसरे से बात कर सकें। Web Locks API, जो navigator.locks के रूप में उपलब्ध है, बिल्कुल यही सुविधा देता है। यह स्क्रिप्ट्स को एक नामी लॉक (named lock) के लिए रिक्वेस्ट करने की अनुमति देता है जिसे ब्राउज़र एक ही origin से संबंधित सभी कॉन्टेक्स्ट्स में लागू करता है। यदि कोई लॉक पहले से ही किसी के पास है, तो अन्य कॉलर्स को तब तक कतार में रखा जाता है जब तक कि होल्डर उसे रिलीज़ न कर दे या ब्राउज़र उसे रद्द न कर दे (उदाहरण के लिए, जब टैब क्रैश हो जाता है)। कोई बाहरी सर्वर नहीं, कोई पोलिंग नहीं, बस नेटिव ब्राउज़र कोऑर्डिनेशन।

लॉक-आधारित रिफ्रेश फ्लो को लागू करना

  1. 401 को डिटेक्ट करें – Axios interceptor पहले की तरह ही अनधिकृत (unauthorized) रिस्पॉन्स को पकड़ लेता है।
  2. एक्सक्लूसिव लॉक मांगें – टैब navigator.locks.request('auth_token_refresh_lock', async lock => { … }) को कॉल करता है। एक समय में केवल एक ही टैब कॉलबैक में प्रवेश कर सकता है।
  3. नेटवर्क पर जाने से पहले दोबारा जांचें – लॉक के अंदर, localStorage से एक टाइमस्टैम्प (या टोकन खुद) पढ़ें। यदि टाइमस्टैम्प कुछ सेकंड से कम पुराना है, तो इसका मतलब है कि किसी अन्य टैब ने पहले ही टोकन रिफ्रेश कर लिया है; वर्तमान टैब नेटवर्क कॉल को छोड़ देता है और सीधे स्टोरेज से नया JWT पढ़ लेता है।
  4. यदि आवश्यक हो तो रिफ्रेश करें – यदि स्टोर किया गया टाइमस्टैम्प पुराना (stale) है, तो रिफ्रेश रिक्वेस्ट भेजें, नया टोकन और वर्तमान समय localStorage में स्टोर करें, और फिर कॉलबैक से रिटर्न करके लॉक को रिलीज़ करें।
  5. कतारबद्ध (queued) रिक्वेस्ट को फिर से शुरू करें – अन्य सभी टैब जो इंतज़ार कर रहे थे, एक के बाद एक लॉक प्राप्त करते हैं, नया टाइमस्टैम्प देखते हैं, और बिना कोई दूसरी रिक्वेस्ट किए काम पूरा कर लेते हैं।
async function refreshIfNeeded() {
  await navigator.locks.request('auth_token_refresh_lock', async lock => {
    const lastRefresh = Number(localStorage.getItem('token_refreshed_at') || 0);
    const now = Date.now();
    if (now - lastRefresh < 5_000) return; // another tab already refreshed

    const newToken = await callRefreshEndpoint(); // actual network call
    localStorage.setItem('jwt', newToken);
    localStorage.setItem('token_refreshed_at', now.toString());
  });
}

यह पैटर्न गारंटी देता है कि कितने भी टैब खुले हों, सर्वर तक केवल एक ही रिफ्रेश रिक्वेस्ट पहुँचती है।

लाभ जिन्हें आप माप सकते हैं

  • नेटवर्क दक्षता – एक रिक्वेस्ट पाँच की जगह ले लेती है, जिससे बैंडविड्थ और सर्वर लोड में भारी कमी आती है।
  • सेशन सुरक्षा – Refresh Token Rotation के साथ, सर्वर पुराने refresh token का केवल एक बार उपयोग देखता है, इसलिए वह सेशन को कभी भी कॉम्प्रोमाइज्ड के रूप में मार्क नहीं करता है।
  • लचीलापन – यदि लॉक पकड़े हुए टैब क्रैश हो जाता है, तो ब्राउज़र स्वचालित रूप से लॉक को रिलीज़ कर देता है, जिससे डेडलॉक (deadlock) की स्थिति नहीं बनती जो अन्यथा सभी टैब को रोक सकती थी।
  • स्केलेबिलिटी – यूज़र्स बिना कैस्केड लॉगआउट (cascade logout) के जोखिम के दर्जनों टैब खोल सकते हैं, क्योंकि कोऑर्डिनेशन ब्राउज़र के भीतर ही रहता है।

दूसरी तरफ: ब्राउज़र सपोर्ट और फॉलबैक

Web Locks API एक अपेक्षाकृत नई सुविधा है। आधुनिक Chromium-आधारित ब्राउज़र और Firefox के हालिया वर्ज़न इसे लागू करते हैं, लेकिन पुराने ब्राउज़र और Safari में नेटिव सपोर्ट की कमी है। ऐसे वातावरण में जहाँ API उपलब्ध नहीं है, डेवलपर्स को क्रॉस-टैब सिग्नलिंग के करीब पहुँचने के लिए कम विश्वसनीय तकनीक का सहारा लेना पड़ता है—जैसे कि localStorage के माध्यम से एक कस्टम इवेंट ब्रॉडकास्ट करना या shared worker का उपयोग करना। इन वर्कअराउंड्स में वह ऑटोमैटिक डेड-लॉक प्रोटेक्शन नहीं होता है जो navigator.locks प्रदान करता है, इसलिए उनका उपयोग सावधानी से किया जाना चाहिए।

आगे क्या देखें

  • मानकीकरण की प्रगति – API के अपनाए जाने के रुझान (adoption curve) पर नज़र रखें; व्यापक समर्थन लॉक-आधारित दृष्टिकोण को किसी भी क्रॉस-टैब समन्वय (cross-tab coordination) के लिए डिफ़ॉल्ट बना देगा।
  • लाइब्रेरी रैपर्स – कुछ ओपन-सोर्स यूटिलिटीज पहले से ही लॉक रिक्वेस्ट पैटर्न को एब्स्ट्रैक्ट कर रही हैं, जिससे मौजूदा Axios interceptors में इसे जोड़ना आसान हो जाता है।
  • सुरक्षा ऑडिट – हालांकि लॉक कॉनकरेंसी (concurrency) की समस्या को हल करता है, फिर भी रिफ्रेश एंडपॉइंट को उचित टोकन रोटेशन और रेट लिमिटिंग लागू करनी चाहिए, क्योंकि यदि लॉक को बायपास कर दिया जाता है, तो एक अकेला दुर्भावनापूर्ण टैब अभी भी सर्वर को अनुरोधों से भर सकता है।

निष्कर्ष सरल है: खुले टैब के सेट को एक डिस्ट्रिब्यूटेड सिस्टम की तरह मानें और उन्हें एक नेटिव सिंक्रोनाइज़ेशन प्रिमिटिव प्रदान करें। टोकन-रिफ्रेश फ्लो में Web Locks API को जोड़कर, डेवलपर्स "ब्राउज़र टैब टोकन ट्रैप" को खत्म कर सकते हैं और उपयोगकर्ताओं को लॉग इन रख सकते हैं, चाहे वे कितने भी टैब एक साथ इस्तेमाल कर रहे हों।