API key और OAuth अलग-अलग समस्याएँ हल करते हैं, और दोनों में से चुनाव एक ही सवाल से शुरू होता है: इस ढाँचे में कोई तीसरा पक्ष है या नहीं?

अगर आपका server किसी और के API को अपने ही नाम से बुलाता है, तो key चाहिए। अगर किसी और का ऐप्लिकेशन आपके API को आपके उपयोगकर्ता के नाम से बुलाता है, तो OAuth चाहिए। जहाँ तीसरा पक्ष है ही नहीं, वहाँ OAuth औपचारिकता बढ़ाता है, सुरक्षा नहीं।

आगे: असल फ़र्क़ कहाँ है, पिछले कुछ वर्षों में OAuth में क्या बदला, और API key की वह ख़ासियत जिस पर लगभग कोई नहीं लिखता, हालाँकि वही तय करती है कि प्रोडक्शन में आप उसके साथ कैसे रहेंगे।

API key: एक पंक्ति जो कहती है "इस प्रोग्राम को इजाज़त है"

Key एक लंबी और यादृच्छिक पंक्ति है, जिसे आप request के header में रखते हैं:

X-Api-Key: lix_live_9f2c...

Server उस key को खोजता है, समझता है कि वह किस खाते की है, और request को आगे जाने देता है। पूरा तंत्र बस इतना ही है।

इससे जो गुण निकलते हैं:

  • key अपने आप समाप्त नहीं होती। जब तक कोई उसे रद्द न करे, वह चलती रहती है;
  • key किसी प्रोग्राम की पहचान है, किसी व्यक्ति की नहीं। टीम में किसने कॉल किया, यह आमतौर पर दिखता ही नहीं;
  • key वह सब करने देती है जो खाता कर सकता है, बशर्ते आपने अधिकार अलग से सीमित न किए हों;
  • key ही इकलौता रहस्य है। वह लीक हुई तो पहुँच लीक हो गई — बीच में कोई पड़ाव नहीं।

OAuth: सहमति के बारे में एक प्रोटोकॉल

OAuth 2.0 (RFC 6749) दूसरे सवाल का जवाब देता है। इसमें चार पक्ष होते हैं: डेटा का मालिक, वह ऐप्लिकेशन जो उसे चाहता है, एक authorization server, और वह server जिसके पास डेटा है।

प्रवाह मोटे तौर पर ऐसा है। ऐप्लिकेशन व्यक्ति को सेवा के अपने पन्ने पर भेजता है। वहाँ वह देखता है कि कौन किस चीज़ के लिए पूछ रहा है, और सहमति देता है। ऐप्लिकेशन को एक code मिलता है, वह उसे access token से बदलता है और उसी से API बुलाता है। Token की उम्र छोटी होती है — मिनटों या घंटों की; समाप्त होने पर ऐप्लिकेशन refresh token देकर नया ले लेता है।

इससे जो मिलता है और key सैद्धांतिक रूप से दे ही नहीं सकती:

  • उपयोगकर्ता का पासवर्ड ऐप्लिकेशन तक कभी नहीं पहुँचता। पूरा मतलब यहीं है;
  • अधिकार scope में बँट जाते हैं। "लिंक पढ़ना" और "लिंक मिटाना" अलग-अलग अनुमतियाँ हैं;
  • सहमति दिखती है और वापस ली जा सकती है। उपयोगकर्ता जुड़े हुए ऐप्लिकेशनों की सूची देखता है और बाक़ी को छुए बिना किसी एक को हटा सकता है;
  • token ख़ुद ही बेकार हो जाते हैं। चुराया हुआ access token एक घंटे बाद किसी काम का नहीं रहता।

क़ीमत है जटिलता: authorization server, ऐप्लिकेशनों का पंजीकरण, सहमति की स्क्रीन, refresh token का भंडारण और बदलाव, और हर कॉल पर समाप्ति संभालना।

उन कसौटियों पर तुलना जो सचमुच फ़ैसला तय करती हैं

API key OAuth 2.0
किसे प्रमाणित करता है प्रोग्राम को उस उपयोगकर्ता को जिसकी ओर से प्रोग्राम काम कर रहा है
अवधि अनिश्चित access token: मिनटों से घंटों तक
पहुँच कैसे ख़त्म होती है key रद्द करके सहमति या token वापस लेकर
अधिकारों का दायरा आमतौर पर पूरा खाता हर क्रिया के लिए अलग scope
तीसरे पक्ष के पास रहस्य ख़ुद key केवल token, पासवर्ड कभी नहीं
जोड़ने की मेहनत एक header authorization server और पूरा चक्र
कहाँ ठीक बैठता है server से server, स्क्रिप्ट, भीतरी एकीकरण सार्वजनिक ऐप, मार्केटप्लेस, "… से लॉग इन"

चुनने का नियम

सवाल यह नहीं कि निरपेक्ष रूप से कौन ज़्यादा सुरक्षित है, बल्कि यह कि कौन किसे पहुँच सौंप रहा है।

आपका server → किसी और का API, खाता आपका
    → API key

किसी और का ऐप → आपका API, खाता आपके उपयोगकर्ता का
    → OAuth

निर्धारित समय पर चलने वाला काम, CI, backend एकीकरण
    → API key

उपयोगकर्ता को हर ऐप के हिसाब से पहुँच देखनी और हटानी हो
    → OAuth

Postback लेना key का पाठ्यपुस्तक वाला उदाहरण है। जब आपका server हमारे server को बताता है कि कोई ऑर्डर चुका दिया गया, उस आदान-प्रदान में कोई उपयोगकर्ता है ही नहीं, सहमति देने वाला कोई नहीं, और सहमति की स्क्रीन रखने की जगह भी नहीं। उल्टी दिशा के webhook पर भी यही बात लागू होती है।

जब आपका ध्यान नहीं था, तब OAuth बदल गया

इस विषय के आधे लेख 2015 वाले OAuth का वर्णन करते हैं। उसके बाद वह काफ़ी सिमट चुका है।

जनवरी 2025 में IETF ने RFC 9700, Best Current Practice for OAuth 2.0 Security प्रकाशित किया। यह दस्तावेज़ असली हमलों से जुटे वर्षों के अनुभव को एक जगह लाता है और दो ऐसे तरीक़ों को औपचारिक रूप से पुराना घोषित करता है जो पहले स्वीकार्य माने जाते थे:

  • implicit grant — वह, जो token सीधे पता-पट्टी में लौटा देता था;
  • resource owner password credentials — जिसमें ऐप्लिकेशन उपयोगकर्ता से सीधे उसका लॉगिन और पासवर्ड माँगता था। ठीक वही, जिससे छुटकारा दिलाने के लिए OAuth बना था।

इसी के साथ PKCE सभी प्रकार के क्लाइंट के लिए अनिवार्य हो गया, server की ओर वाले भी शामिल, न कि पहले की तरह केवल मोबाइल के लिए।

अलग से जानने लायक़ बात: OAuth 2.1 आज भी मसौदा है, प्रकाशित RFC नहीं। वह इन्हीं बदलावों को एक दस्तावेज़ में समेटता है — अनिवार्य PKCE, redirect URI का ठीक-ठीक मिलान, implicit और password grant की विदाई, query string में token पर रोक। उसे लागू मानक की तरह उद्धृत करना अभी जल्दबाज़ी है।

व्यावहारिक निष्कर्ष: अगर कोई OAuth मार्गदर्शिका implicit flow सुझा रही है, तो वह मार्गदर्शिका पुरानी पड़ चुकी है।

Key की वह कमज़ोरी जिसका ज़िक्र कम होता है

Key समाप्त नहीं होती। इसका मतलब है कि रद्द करना ही आपका इकलौता ज़रिया है। और यहीं असुविधाजनक बात निकलती है: रद्द करना आमतौर पर तात्कालिक नहीं होता।

हर request पर key जाँचने का अर्थ है हर बार डेटाबेस तक जाना। जिस भी API पर सचमुच का ट्रैफ़िक है, वहाँ यह नतीजा कैश कर लिया जाता है। हमारे यहाँ key और खाते का मेल पाँच मिनट कैश में रहता है। यानी "रद्द करें" दबाने और पहुँच सचमुच रुकने के बीच पाँच मिनट तक का अंतर है, और उस दौरान लीक हुई key काम करती रहती है।

यह चूक नहीं, एक सौदा है: कैश न हो तो हर request डेटाबेस का दरवाज़ा खटखटाएगी। key वाले लगभग हर API ने ऐसा ही सौदा किया है, बस इसे खुलकर कहने का चलन नहीं। जानना दो वजहों से ज़रूरी है। पहली, असली लीक में key रद्द करना आख़िरी नहीं पहला क़दम है: उसके बाद देखना पड़ता है कि उन मिनटों में क्या हुआ। दूसरी, यही वह समस्या है जिसे OAuth के छोटी उम्र वाले token दूसरी तरफ़ से सुलझाते हैं — वे डेटाबेस के बिना ही ख़ुद समाप्त हो जाते हैं।

Key के साथ बिना चोट खाए रहना

अगर key से काम चल जाता है — और ज़्यादातर एकीकरणों में चल जाता है — तो न्यूनतम यह है:

  1. अपने पास केवल hash रखिए। Server भेजी गई key के hash को सहेजे हुए hash से मिलाता है; मूल पंक्ति उपयोगकर्ता को बनाते समय एक ही बार दिखाई जाती है। हम SHA-256 से मिलान करते हैं।
  2. Key को एक उपसर्ग दीजिए। lix_live_... जैसी पंक्ति को कोड भंडारों और लॉग पाइपलाइनों के गुप्त-स्कैनर पहचान लेते हैं।
  3. हर एकीकरण के लिए अलग key। तब एक को रद्द करने से बाक़ी नहीं गिरतीं, और अभिलेख से साफ़ दिखता है कि वास्तव में क्या उजागर हुआ।
  4. Key को कभी query string में न डालें। पते वेब server के लॉग में, Referer header में और ब्राउज़र के इतिहास में बैठ जाते हैं। केवल header।
  5. घटना के बाद नहीं, कैलेंडर के हिसाब से बदलिए। जो key एक बार बदली जा चुकी है, वह अगली बार जल्दी बदलती है। जो कभी नहीं बदली, वह अंत में चार जगहों पर जड़ी हुई निकलेगी।
  6. आख़िरी इस्तेमाल की तारीख़ देखिए। छह महीने से अनछुई key कोई अतिरिक्त इंतज़ाम नहीं, खुला हुआ दरवाज़ा है।

हम क्या इस्तेमाल करते हैं

Lix.li का API key से प्रमाणन करता है: X-Api-Key header, key डैशबोर्ड में बनती और रद्द होती हैं, मिलान hash से, और हर key पर अलग request सीमा। OAuth नहीं है, और यह सोच-समझकर है: इस API के इस्तेमाल server की ओर के हैं — लिंक बनाना, आँकड़े लेना, conversion स्वीकार करना — और इनमें से किसी में भी ऐसा तीसरा पक्ष नहीं जिसे उपयोगकर्ता की सहमति चाहिए।

अगर कभी दूसरों के ऐप्लिकेशनों को हमारे ग्राहकों के खातों में घुसने देने की ज़रूरत आ पड़े, तो key से काम नहीं चलेगा: उपयोगकर्ता को दिखना चाहिए कि उसने किसे क्या दिया है, और वह बाक़ी को तोड़े बिना एक ऐप्लिकेशन हटा सके। ठीक वहीं OAuth औपचारिकता होना बंद करके इकलौता ईमानदार विकल्प बन जाता है।

कॉल ख़ुद API दस्तावेज़ में लिखे हैं, इसमें यह भी कि ग़लत key और रद्द की गई key पर कौन-से response code आते हैं। पड़ोसी विषयों में से दो अलग से देखने लायक़ हैं: webhook, अगर आप घटनाएँ पूछने के बजाय पाना चाहते हैं, और 301, 302, 307, 308 redirect का फ़र्क़ — क्योंकि 301 POST को GET में बदल देता है, और यह postback लेने वालों को सीधे छूता है।