Web Locks API पाच उघडलेल्या टॅब्सना एकाच वेळी auth सर्व्हरवर refresh-token कॉल्सचा मारा करण्यापासून रोखू शकते, ज्यामुळे वापरकर्त्यांना अचानक लॉगआउट होण्यापासून वाचवता येते. टॅब्समधील रिफ्रेश प्रक्रियेत समन्वय साधल्यामुळे, Refresh Token Rotation वापरले जात असताना सामान्यतः सेशन संपवण्यास (session-kill) कारणीभूत ठरणाऱ्या मोठ्या संख्येने येणाऱ्या विनंत्यांच्या जागी केवळ एकच विनंती पाठवली जाते.
मल्टी-टॅब सेशनमधील छुपा ओव्हरलोड
एक सामान्य सिंगल-पेज ॲप Axios interceptor वापरते जो 401 रिस्पॉन्सवर लक्ष ठेवतो, isRefreshing नावाचा Boolean flag बदलतो आणि नवीन JWT येईपर्यंत बाहेर जाणाऱ्या सर्व विनंत्या रांगेत (queue) ठेवतो. एका टॅबमध्ये तपासले असता, ही प्रक्रिया उत्तम प्रकारे काम करते.
तेच ॲप पाच टॅब्समध्ये उघडा, access token संपू द्या, आणि पाचही टॅब्सना एकाच मिलीसेकंदात 401 एरर जाणवेल. प्रत्येक टॅबला वाटते की त्याला रिफ्रेश करणे आवश्यक आहे, त्यामुळे पाच सारख्याच refresh-token विनंत्या auth सर्व्हरकडे धाव घेतात. Refresh Token Rotation—एक सुरक्षा उपाय जो नवीन टोकन जारी होताच जुने रिफ्रेश टोकन अवैध ठरवतो—यामुळे सर्व्हर दुसऱ्या विनंतीला 'replay attack' समजतो, सेशनशी छेडछाड झाल्याचे चिन्ह (flag) देतो आणि ते रद्द करतो. परिणामी, वापरकर्ता एका क्षणात सर्व टॅब्समधून लॉगआउट होतो.
याचे मूळ कारण JavaScript चे isolation model आहे. isRefreshing सारखा व्हेरिएबल फक्त त्याच टॅबमध्ये असतो ज्याने तो सेट केला आहे; इतर टॅब्सना रिफ्रेश प्रक्रिया आधीच सुरू आहे हे समजण्याचे कोणतेही साधन नसते. हे एक क्लासिक concurrency problem आहे, परंतु येथे "processes" हे threads ऐवजी ब्राउझर टॅब्स आहेत.
क्रॉस-टॅब लॉक हे योग्य साधन का आहे
आपल्याला अशा पद्धतीची गरज आहे ज्याद्वारे टॅब्स एकमेकांशी सामायिक संसाधनाबद्दल (shared resource)—या प्रकरणात, नवीन JWT बद्दल—संवाद साधू शकतील. Web Locks API, जो navigator.locks म्हणून उपलब्ध आहे, नेमके तेच प्रदान करतो. हे स्क्रिप्ट्सना एका नावाच्या लॉकची विनंती करण्याची परवानगी देते, ज्याची अंमलबजावणी ब्राउझर एकाच origin च्या सर्व संदर्भांमध्ये (contexts) करतो. जर एखादा लॉक आधीच घेतलेला असेल, तर तो धारक सोडईपर्यंत किंवा ब्राउझर तो रद्द करेपर्यंत (उदाहरणार्थ, टॅब क्रॅश झाल्यास) इतर विनंत्या रांगेत ठेवल्या जातात. यासाठी कोणत्याही बाह्य सर्व्हरची किंवा polling ची गरज नाही, फक्त नेटिव्ह ब्राउझर समन्वय पुरेसा आहे.
लॉक-आधारित रिफ्रेश फ्लोची अंमलबजावणी
- 401 शोधणे – Axios interceptor पूर्वीप्रमाणेच अनधिकृत (unauthorized) रिस्पॉन्स पकडतो.
- Exclusive lock साठी विनंती करणे – टॅब
navigator.locks.request('auth_token_refresh_lock', async lock => { … })कॉल करतो. एका वेळी फक्त एकच टॅब callback मध्ये प्रवेश करू शकतो. - नेटवर्क कॉल करण्यापूर्वी पुन्हा तपासणे – लॉकच्या आत,
localStorageमधून टाइमस्टॅम्प (किंवा स्वतः टोकन) वाचा. जर टाइमस्टॅम्प काही सेकंदांपेक्षा कमी जुना असेल, तर दुसऱ्या टॅबने आधीच टोकन रिफ्रेश केले आहे; सध्याचा टॅब नेटवर्क कॉल वगळतो आणि थेट स्टोरेजमधून नवीन JWT वाचतो. - गरज असल्यास रिफ्रेश करणे – जर साठवलेला टाइमस्टॅम्प जुना (stale) असेल, तर रिफ्रेश विनंती पाठवा, नवीन टोकन आणि सध्याची वेळ
localStorageमध्ये साठवा, आणि त्यानंतर callback मधून रिटर्न करून लॉक सोडा. - रांगेतील विनंत्या पुन्हा सुरू करणे – प्रतीक्षा करणारे इतर सर्व टॅब्स एकानंतर एक लॉक मिळवतात, नवीन टाइमस्टॅम्प पाहतात आणि कोणतीही नवीन विनंती न करता प्रक्रिया पूर्ण करतात.
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 मुळे, सर्व्हर जुन्या रिफ्रेश टोकनचा फक्त एकदाच वापर पाहतो, त्यामुळे सेशनशी छेडछाड झाल्याचे चिन्ह (flag) कधीही दिले जात नाही.
- लवचिकता (Resilience) – जर लॉक धारण करणारा टॅब क्रॅश झाला, तर ब्राउझर आपोआप लॉक मुक्त करतो, ज्यामुळे डेडलॉक (deadlock) टाळता येतो जो अन्यथा सर्व टॅब्स थांबवू शकला असता.
- स्केलेबिलिटी (Scalability) – वापरकर्ते एकामागून एक लॉगआउट होण्याचा धोका न पत्करता डझनभर टॅब्स उघडू शकतात, कारण समन्वय ब्राउझरच्या आतच राहतो.
दुसरी बाजू: ब्राउझर सपोर्ट आणि फॉलबॅक (fallbacks)
Web Locks API हे तुलनेने नवीन फीचर आहे. आधुनिक Chromium-आधारित ब्राउझर आणि Firefox च्या अलीकडील आवृत्त्यांमध्ये हे उपलब्ध आहे, परंतु जुने ब्राउझर आणि Safari मध्ये नेटिव्ह सपोर्ट नाही. ज्या वातावरणात API उपलब्ध नाही, तिथे डेव्हलपर्सना क्रॉस-टॅब सिग्नलिंगसाठी localStorage द्वारे कस्टम इव्हेंट ब्रॉडकास्ट करणे किंवा shared worker वापरणे यांसारख्या कमी विश्वसनीय तंत्रांचा आधार घ्यावा लागतो. या उपायांमध्ये navigator.locks प्रदान करते तसे ऑटोमॅटिक डेड-लॉक प्रोटेक्शन नसते, त्यामुळे त्यांचा वापर काळजीपूर्वक केला पाहिजे.
पुढे काय पाहावे
- मानकीकरण प्रगती – API च्या अवलंबनाचा आलेख (adoption curve) लक्षपूर्वक पाहत राहा; व्यापक पाठिंब्यामुळे कोणत्याही क्रॉस-टॅब समन्वयासाठी (cross-tab coordination) लॉक-आधारित दृष्टिकोन हा डीफॉल्ट बनेल.
- लायब्ररी रॅपर्स – काही ओपन-सोर्स युटिलिटीज आधीच लॉक विनंती पॅटर्नचे अमूर्तकरण (abstracting) करत आहेत, ज्यामुळे ते विद्यमान Axios interceptors मध्ये जोडणे सोपे होईल.
- सुरक्षा ऑडिट – जरी लॉकमुळे कॉनकरन्सीची (concurrency) समस्या सुटत असली तरी, रिफ्रेश एंडपॉइंटने (refresh endpoint) योग्य टोकन रोटेशन आणि रेट लिमिटिंग (rate limiting) लागू करणे आवश्यक आहे, कारण जर लॉक बायपास झाला, तर एकही दुर्भावनापूर्ण (malicious) टॅब सर्व्हरवर विनंत्यांचा पूर आणू शकतो.
निष्कर्ष साधा आहे: उघडलेल्या टॅब्सच्या संचाकडे एक डिस्ट्रिब्युटेड सिस्टम (distributed system) म्हणून पहा आणि त्यांना एक नेटिव्ह सिंक्रोनाइझेशन प्रिमिटिव्ह (native synchronization primitive) द्या. Web Locks API ला टोकन-रिफ्रेश फ्लोमध्ये जोडून, डेव्हलपर्स "browser tab token trap" पासून सुटका मिळवू शकतात आणि वापरकर्ते कितीही टॅब्स वापरत असले तरी त्यांना लॉग इन ठेवू शकतात.
