← All posts

हर token validation हमारे origin तक पहुँचती थी। अब JWKS edge पर रहता है।

Authagonal·July 20, 2026
authoidcjwkscdncloudflarecachingkey-rotation

हमारे किसी JWT को validate करने के लिए, कोई service issuer से दो सार्वजनिक दस्तावेज़ माँगती है: /.well-known/openid-configuration पर पड़ा discovery document, और वह JWKS जिसकी ओर वह इशारा करता है — यानी उन public keys का समूह जिनसे token हस्ताक्षरित होते हैं। ये वही चीज़ें हैं जिनकी सबसे ज़्यादा माँग होती है और जो सबसे कम गोपनीय हैं। ये public keys हैं, जो परिभाषा से ही सार्वजनिक होती हैं, और ऐसा metadata हैं जो केवल तभी बदलता है जब हम rotate करते हैं। और कुछ समय पहले तक, इनमें से हर fetch पूरा सफ़र तय करके वापस हमारे origin तक आती थी। और चूँकि हम multi-tenant हैं, हालात इस वाक्य से भी बदतर थे।

origin ऐसा काम कर रहा था जिसकी उसे कोई वजह ही नहीं थी

हर tenant अपने आप में एक issuer है, अपने .well-known document और अपने JWKS के साथ। और हर relying party, हर resource server, हर SDK जो किसी token को validate करता है, इन दस्तावेज़ों को खींचता है — cold start पर, जब उसका अपना छोटा-सा cache ख़त्म होता है, हर service instance पर एक बार। प्रति-tenant issuers को प्रति-service validators से और उसे cache misses से गुणा कीजिए, तो आपको requests का एक ऐसा फ़व्वारा मिलता है जो पूरी ताक़त से बरस रहा हो — और यह सब application पर आकर टूटता है, और यह सब ऐसे दस्तावेज़ों के लिए जो हर माँगने वाले के लिए byte-दर-byte एक-जैसे हैं और तभी बदलते हैं जब हम कोई key rotate करते हैं।

यह ठीक वही किताबी नमूना है किसी ऐसी चीज़ का जिसे cache किया जाना चाहिए: सार्वजनिक, एक-जैसी, बहुत कम बदलने वाली। इसके बजाय app, public keys को हर बार नए सिरे से (dynamically) तैयार कर रहा था — और वह भी बाक़ी सबकी token validation के hot path पर। इन keys का हर request पर परिकलित होने से कोई वास्ता ही नहीं था।

इन्हें edge पर रखना

बदलाव अपने आप में छोटा है: discovery और JWKS responses पर ईमानदार Cache-Control headers सेट कर दीजिए ताकि Cloudflare उन्हें edge पर cache कर ले। अब कोई validator नज़दीकी Cloudflare point of presence तक पहुँचता है, और origin हर दस्तावेज़ को हर validation पर एक बार के बजाय मोटे तौर पर प्रति PoP प्रति TTL एक बार परोसता है। Discovery को cache करना बेहद आसान है — यह लगभग कभी नहीं बदलता। JWKS ही वह चीज़ है जिस पर आपको गहराई से सोचना पड़ता है, क्योंकि JWKS वह इकलौता दस्तावेज़ है जिसका पूरा काम ही यह है कि वह ठीक उसी वक़्त बदले जब आप कोई key rotate करते हैं — और जिस चीज़ को ठीक उसी एक पल पर ताज़ा रहना है जब वह बदलती है, उसे cache करना वहीं है जहाँ लोग ख़ुद को चोट पहुँचा बैठते हैं।

एक cache किया हुआ JWKS आपको कैसे काट खाता है

Key rotation और उसके साथ एक cache किया हुआ key set — यह एक जाल है, और यह सबसे बुरी मुमकिन दिशा में नाकाम होता है। एक नई signing key पर rotate कीजिए, उससे token जारी करना शुरू कीजिए, और जिस validator ने नई key के आने से पहले JWKS खींचा था, उसके पास एक बासी प्रति पड़ी है। एक token आता है जो नई key का id लिए हुए है; validator उसे ढूँढता है, नहीं पाता, और token को अस्वीकार कर देता है। वह token पूरी तरह वैध है। signature असली है। user ने कुछ भी ग़लत नहीं किया। आपके अपने edge cache ने अभी-अभी एक जायज़ login को 401 लौटा दिया।

ग़ौर कीजिए कि यह किस दिशा में नाकाम होता है। एक बासी private key कोई घटना ही नहीं है — बस आपने अभी नई key इस्तेमाल करना शुरू नहीं किया है। पर एक बासी public key set एक ऐसी outage है जो आपने ख़ुद अपने ऊपर ओढ़ी है, और जिस cache ने इसे पैदा किया उसे तो आपने जान-बूझकर, origin traffic बचाने के लिए, लाया था। पूरी योजना की सुरक्षा rotation पर ही जीती या मरती है।

rotation-safe पैटर्न

सुरक्षा पूरी तरह क्रम में है, और यह क्रम एक atomic swap के बिल्कुल उलट है। तीन नियम:

  • हस्ताक्षर करने से पहले प्रकाशित करो। नई key सबसे पहले JWKS में जाती है, और आप उससे एक भी token पर तब तक हस्ताक्षर नहीं करते जब तक वह JWKS — नई key id वग़ैरह समेत — कम-से-कम एक पूरे cache TTL तक edge पर live न रह ले। नई key लिए हुए कोई भी token जब तक किसी validator तक पहुँच पाता है, तब तक validator के cache किए हुए key set में वह key पहले से मौजूद होती है।
  • समय-सीमा ख़त्म होने पर सेवानिवृत्त करो, rotation पर नहीं। पुरानी key तब तक JWKS में प्रकाशित रहती है जब तक उसका हस्ताक्षर किया हुआ आख़िरी token भी अपनी समय-सीमा पार न कर ले। पूरे overlap के दौरान पुरानी और नई, दोनों साथ-साथ रहती हैं। जैसे ही आप rotate करें वैसे ही पुरानी key खींच ली, तो आप उसके हस्ताक्षर किए हुए हर उस token को बीच मँझधार छोड़ देंगे जो अब भी वैध है।
  • TTL, overlap से छोटा। edge cache का max-age, और उसमें clock skew के लिए थोड़ी गुंजाइश जोड़कर, key-overlap की खिड़की से छोटा होना चाहिए। cache को बासी होने की छूट है; पर उसे कभी भी उस खिड़की से ज़्यादा देर तक बासी रहने की छूट नहीं है जिसमें दोनों keys अच्छी हैं। यही एक असमानता एक आक्रामक ढंग से cache किए गए JWKS को सुरक्षित बनाती है।

सब मिलाकर, rotation एक तयशुदा क्रम वाला crossfade बन जाता है: नई key जोड़ो, edge और हर validator के उसे देख लेने के लिए एक TTL रुको, फिर उससे हस्ताक्षर करना शुरू करो, पुराने token के धीरे-धीरे बूढ़े होकर ख़त्म हो जाने का इंतज़ार करो, और फिर पुरानी key हटा दो। हर क़दम एक ऐसे cache के ख़िलाफ़ भी सुरक्षित है जो एक TTL पीछे चल रहा हो, क्योंकि TTL को जान-बूझकर हर उस खिड़की से छोटा चुना गया था जितना पीछे कोई cache हो सकता है।

सबक़, सार-रूप में

Caching आम तौर पर latency से जुड़ा फ़ैसला होता है। public keys को cache करना सहीपन (correctness) का फ़ैसला है, क्योंकि जिस चीज़ को आप cache कर रहे हैं वही तय करती है कि कौन-से token असली हैं। आप इसे बेशक edge पर रख सकते हैं — और रखना भी चाहिए, क्योंकि यह सार्वजनिक भी है और hot भी — पर तभी, जब rotation को एक swap के बजाय एक क्रमबद्ध overlap के रूप में व्यक्त किया गया हो, और तभी, जब cache TTL साबित तौर पर उस overlap से छोटा हो। इसे ठीक कर लीजिए, और आपके auth system के सबसे व्यस्त, सबसे ज़्यादा cache होने लायक़ दस्तावेज़ आपके origin को छूना बंद कर देते हैं — और किसी को कभी फ़र्क़ तक महसूस नहीं होता, जो कि असल में मक़सद ही यही है।