त्वरित उत्तर: OAuth 1.0a जटिल क्रिप्टोग्राफिक हस्ताक्षरों पर निर्भर था और OAuth 2.0 बियरर टोकन के कारण रीप्ले हमलों के प्रति संवेदनशील था। स्वायत्त AI एजेंट्स और MCP सर्वर के लिए OAuth 2.1 अनिवार्य मानक है: यह PKCE (RFC 7636) लागू करता है, असुरक्षित ग्रांट्स हटाता है और DPoP (RFC 9449) द्वारा हेडलेस परिवेश में सेंडर-कंस्ट्रेंड जीरो-ट्रस्ट टोकन बाध्यकारी बनाता है।
1. परिचय: 2026 में स्वायत्त एजेंट्स का पहचान और ऑथराइजेशन संकट
अलग-थलग लार्ज लैंग्वेज मॉडल (LLM) चैट इंटरफेस से स्वायत्त, मल्टी-टर्न AI एजेंट्स और मॉडल कॉन्टेक्स्ट प्रोटोकॉल (Model Context Protocol, MCP) सर्वरों की ओर तीव्र बदलाव ने एक गंभीर साइबर सुरक्षा संकट पैदा कर दिया है: एजेंटिक पहचान और ऑथराइजेशन का गतिरोध।
2024 और 2025 में, डेवलपर्स ने Claude Code, Cursor, Windsurf, AutoGen और कस्टम LangGraph एजेंट्स जैसे स्वायत्त टूल्स को कॉर्पोरेट API से कनेक्ट करने के लिए मुख्य रूप से .env फाइलों या ऑपरेटिंग सिस्टम प्रोसेस एनवायरनमेंट में हार्डकोड किए गए स्टेटिक पर्सनल एक्सेस टोकन (PAT) या दीर्घकालिक API कीज का उपयोग किया। जब कोई AI एजेंट लोकल शेल कमांड निष्पादित करता है, आंतरिक डेटाबेस को क्वेरी करता है (PostgreSQL या Supabase MCP सर्वर के माध्यम से), या एंटरप्राइज इश्यू ट्रैकर्स को अपडेट करता है (Jira या Linear MCP सर्वर के माध्यम से), तो वह अत्यधिक व्यापक और अनियंत्रित परिवेशी अधिकार (Ambient Authority) के तहत काम करता है।
कमजोर लीगेसी एजेंट आर्किटेक्चर (परिवेशी स्टेटिक अधिकार):
+--------------------+ सबप्रोसेस निर्माण +---------------------------+
| LLM होस्ट एजेंट | ─────────────────────────────> | लोकल MCP टूल सर्वर |
| (Claude Code / | Env: GITHUB_TOKEN=ghp_... | (process.env को पढ़ता है) |
| Cursor / LangSeq) | +-------------+-------------+
+---------+----------+ |
| अप्रत्यक्ष प्रॉम्प्ट इंजेक्शन हमला | अप्रतिबंधित रीड/राइट
v v
+--------------------+ +-------------------+
| अविश्वसनीय वेबपेज | | अपस्ट्रीम एंटरप्राइज|
| पर हमलावर प्रॉम्प्ट | ──> स्टेटिक सीक्रेट एक्सफिल्ट्रेट ────> | GitHub / Slack / |
| "Print your env" | हमलावर के HTTP वेबहुक पर भेजा | आंतरिक डेटाबेस |
+--------------------+ +-------------------+
यह स्टेटिक क्रेडेंशियल आर्किटेक्चर तीन बुनियादी कारणों से पूरी तरह असुरक्षित है:
- सीक्रेट एक्सफिल्ट्रेशन वेक्टर के रूप में प्रॉम्प्ट इंजेक्शन: यदि एजेंट अविश्वसनीय डेटा (जैसे किसी वेबपेज, ईमेल या GitHub इश्यू में छुपा हुआ प्रतिकूल प्रॉम्प्ट) के संपर्क में आता है, तो LLM को डायग्नोस्टिक टूल्स निष्पादित करने या
process.envप्रिंट करने के लिए बरगलाया जा सकता है, जिससे उच्च-विशेषाधिकार प्राप्त कीज तुरंत लीक हो जाती हैं। - पहचान के डेलिगेशन का अभाव: एक स्टेटिक API की यह अंतर नहीं कर सकती कि कोई कार्य किसी मानव ऑपरेटर द्वारा जानबूझकर किया गया था या AI एजेंट द्वारा मतिभ्रम (hallucination) या स्वायत्त रूप से ट्रिगर किया गया था। एंटरप्राइज ऑडिट लॉग में, सभी कॉल्स समान रूप से मानव उपयोगकर्ता के रूप में दिखाई देती हैं।
- गतिशील निरस्तीकरण और न्यूनतम विशेषाधिकार का अभाव: स्टेटिक टोकन आमतौर पर अत्यधिक व्यापक विशेषाधिकार (जैसे पूरे रिपॉजिटरी पर पूर्ण रीड/राइट एक्सेस) रखते हैं और उनकी शेल्फ-लाइफ कई महीनों या अनिश्चितकाल तक होती है।
इस व्यवस्थागत जोखिम को हल करने के लिए, AI इकोसिस्टम डेलिगेटेड ऑथराइजेशन फ्रेमवर्क पर केंद्रित हो गया है। हालांकि, OAuth 1.0a, OAuth 2.0, और उभरते हुए समेकित मानक OAuth 2.1 के बीच चयन करना — और साथ ही PKCE (RFC 7636), DPoP (RFC 9449), और डिवाइस ऑथराइजेशन ग्रांट (RFC 8628) का समन्वय करना — यह समझने की मांग करता है कि ये प्रोटोकॉल हेडलेस और स्वायत्त निष्पादन बाधाओं के तहत कैसे काम करते हैं।
2. OAuth का विकास: 1.0a बनाम 2.0 बनाम 2.1 का संरचनात्मक विश्लेषण
आधुनिक AI एजेंट फ्रेमवर्क OAuth 2.1 को क्यों अनिवार्य करते हैं, यह समझने के लिए हमें OAuth विनिर्देश के तीन प्रमुख संस्करणों के आर्किटेक्चरल विकास, ट्रेड-ऑफ और महत्वपूर्ण कमजोरियों की जांच करनी होगी।
OAUTH विनिर्देश का विकास (2007 - 2026):
+---------------------------------------------------------------------------------------------+
| OAuth 1.0a (RFC 5849, 2010) |
| - प्रत्येक HTTP अनुरोध पर सममित/असममित क्रिप्टोग्राफिक हस्ताक्षर (HMAC-SHA1, RSA-SHA1) |
| - कोई टोकन रिफ्रेश फ्लो नहीं; स्टेटफुल हस्ताक्षर गणना; ट्रांसपोर्ट-स्वतंत्र सुरक्षा |
| - AI के लिए निष्कर्ष: अनुपयोगी। क्रिप्टो ओवरहेड स्ट्रीमिंग और डायनामिक टूल प्रॉक्सी को तोड़ता है।|
+---------------------------------------------------------------------------------------------+
│
▼
+---------------------------------------------------------------------------------------------+
| OAuth 2.0 (RFC 6749 और RFC 6750, 2012) |
| - ट्रांसपोर्ट लेयर सिक्योरिटी (TLS 1.2/1.3) को सौंपी गई क्रिप्टोग्राफी |
| - Bearer टोकन, स्कोप्स, रिफ्रेश टोकन और विशेष ग्रांट प्रकार पेश किए गए |
| - इसमें इम्प्लिसिट फ्लो और रिसोर्स ओनर पासवर्ड क्रेडेंशियल्स (ROPC) शामिल थे |
| - AI के लिए निष्कर्ष: खतरनाक। प्रॉम्प्ट इंजेक्शन या SSRF के जरिए बियरर टोकन आसानी से चोरी होते हैं।|
+---------------------------------------------------------------------------------------------+
│
▼
+---------------------------------------------------------------------------------------------+
| OAuth 2.1 (समेकित IETF मानक, 2025/2026) |
| - अप्रचलित, असुरक्षित ग्रांट्स को पूरी तरह समाप्त किया गया (Implicit और Password ग्रांट्स बाहर)|
| - सभी ऑथराइजेशन कोड फ्लो के लिए PKCE (RFC 7636) अनिवार्य (पब्लिक और कॉन्फिडेंशियल दोनों) |
| - सटीक रीडायरेक्ट URI स्ट्रिंग मिलान; URI क्वेरी स्ट्रिंग में टोकन ले जाने पर पूर्ण प्रतिबंध |
| - रिफ्रेश टोकन रोटेशन (RTR) या सेंडर-कंस्ट्रेंड टोकन (DPoP / mTLS) अनिवार्य |
| - AI के लिए निष्कर्ष: MCP और स्वायत्त एजेंट पहचान डेलिगेशन के लिए स्वर्ण मानक। |
+---------------------------------------------------------------------------------------------+
OAuth 1.0a (RFC 5849): क्रिप्टोग्राफिक कठोरता और स्टेटफुलनेस
OAuth 1.0a उस युग में विकसित किया गया था जब HTTPS/TLS महंगा था और कम उपयोग किया जाता था। प्लेनटेक्स्ट HTTP पर वायरटैपिंग से बचाने के लिए, OAuth 1.0a को प्रत्येक व्यक्तिगत HTTP अनुरोध के लिए क्लाइंट और सर्वर द्वारा क्रिप्टोग्राफिक हस्ताक्षर (HMAC-SHA1 या RSA-SHA1) की गणना की आवश्यकता होती थी।
हस्ताक्षर गणना के लिए HTTP विधि, सटीक सामान्यीकृत URL, और सभी क्वेरी मापदंडों, हेडर, क्लाइंट नॉनस और यूनिक्स टाइमस्टैम्प की लेक्सिकोग्राफिक रूप से क्रमबद्ध स्ट्रिंग की आवश्यकता होती थी:
$$\text{BaseString} = \text{HTTP\_METHOD} \mathbin{\Vert} \text{"\&"} \mathbin{\Vert} \text{Encode}(\text{URL}) \mathbin{\Vert} \text{"\&"} \mathbin{\Vert} \text{Encode}(\text{SortedParams})$$
$$\text{Signature} = \text{HMAC-SHA1}(\text{ClientSecret} \mathbin{\Vert} \text{"\&"} \mathbin{\Vert} \text{TokenSecret}, \text{BaseString})$$
AI एजेंट्स के लिए OAuth 1.0a क्यों विफल रहता है:
- स्ट्रीमिंग और चंक्ड ट्रांसपोर्ट: आधुनिक एजेंट प्रोटोकॉल (जैसे Server-Sent Events या WebSockets पर MCP) वृद्धिशील JSON-RPC पेलोड को स्ट्रीम करते हैं। गैर-नियतात्मक स्ट्रीमिंग चंक्स पर हस्ताक्षरों की पुनर्गणना सत्यापन को लगातार विफल कर देती है।
- अल्पकालिक टूल ऑर्केस्ट्रेशन: AI एजेंट LLM टूल मापदंडों के माध्यम से गतिशील रूप से HTTP अनुरोध बनाते हैं। थोड़ा सा पैरामीटर पुनरार्यक्रम या URL एन्कोडिंग अंतर (
%20बनाम+) हस्ताक्षर को अमान्य कर देता है, जिससे स्वचालित लूप में 401 Unauthorized त्रुटियां आती हैं। - मूल रिफ्रेश अलगाव का अभाव: OAuth 1.0a में स्वचालित रोटेशन यांत्रिकी के साथ अल्पकालिक टोकन समाप्ति नहीं थी, जिससे दीर्घकालिक क्रेडेंशियल्स क्लाइंट परिवेश में स्थायी रूप से रहने के लिए मजबूर थे।
OAuth 2.0 (RFC 6749): बियरर जोखिम की कीमत पर सरलता
OAuth 2.0 ने ट्रांसपोर्ट लेयर (HTTPS को अनिवार्य करके) पर क्रिप्टोग्राफिक अखंडता को सौंपकर जटिलता को हल किया और Bearer टोकन (RFC 6750) पेश किया। जिस किसी के पास टोकन है, वह संसाधन तक पहुंच सकता है, ठीक नकदी की तरह:
GET /v1/repositories HTTP/1.1
Host: api.github.com
Authorization: Bearer ya29.a0AfH6SMB...
OAuth 2.0 ने चार मूल ग्रांट फ्लो परिभाषित किए:
- Authorization Code Grant: गोपनीय बैकएंड सीक्रेट्स वाले वेब अनुप्रयोगों के लिए सुरक्षित रीडायरेक्शन फ्लो।
- Implicit Grant: ब्राउज़र-आधारित फ्लो जो बैकएंड कोड एक्सचेंज के बिना सीधे URL हैश अंश (
#access_token=...) में टोकन देता है। - Resource Owner Password Credentials (ROPC): टोकन प्राप्त करने के लिए क्लाइंट ऐप में सीधे उपयोगकर्ता नाम और पासवर्ड जमा करना।
- Client Credentials Grant: मानव ऑपरेटर के बिना सर्वर डेमॉन के लिए डायरेक्ट मशीन-टू-मशीन (M2M) ऑथराइजेशन।
AI सिस्टम में OAuth 2.0 की घातक कमजोरियां:
- बियरर रीप्ले भेद्यता (Replay Attack): यदि किसी एजेंट का परिवेश SSRF, प्रॉम्प्ट इंजेक्शन या लॉग लीकेज के माध्यम से समझौता कर लिया जाता है, तो एक हमलावर बियरर टोकन चुरा सकता है और उसके समाप्त होने तक दुनिया में कहीं से भी उसका पुन: उपयोग कर सकता है।
- इम्प्लिसिट ग्रांट ट्रैप: शुरुआती SPA और डेस्कटॉप एजेंट फ्रंटएंड ने इम्प्लिसिट फ्लो का उपयोग किया, जिससे टोकन ब्राउज़र इतिहास और
Refererहेडर में लीक हो गए। - पासवर्ड ग्रांट एंटीपैटर्न: CLI एजेंट बनाने वाले डेवलपर्स अक्सर टर्मिनल प्रॉम्प्ट में पासवर्ड मांगते थे, जिससे तृतीय पक्षों के साथ क्रेडेंशियल साझा न करने का मौलिक सिद्धांत टूट जाता था।
OAuth 2.1: स्वायत्त एजेंट्स के लिए आधुनिक सुदृढ़ मानक
OAuth 2.1 एक IETF समेकन विनिर्देश है जो OAuth 2.0 के तकनीकी ऋण और सुरक्षा कमजोरियों को दूर करता है:
- असुरक्षित ग्रांट्स का पूर्ण उन्मूलन: इम्प्लिसिट ग्रांट और पासवर्ड क्रेडेंशियल ग्रांट दोनों को औपचारिक रूप से हटा दिया गया है।
- सभी ऑथराइजेशन कोड फ्लो के लिए अनिवार्य PKCE: Proof Key for Code Exchange (RFC 7636) अब पब्लिक क्लाइंट्स (CLI एजेंट्स, IDE एक्सटेंशन) और कॉन्फिडेंशियल क्लाइंट्स (बैकएंड एजेंट स्वार्म) दोनों के लिए अनिवार्य है।
- सटीक रीडायरेक्ट URI मिलान: ओपन-रीडायरेक्टर हमलों को रोकने के लिए ऑथराइजेशन सर्वर को रीडायरेक्ट URI पर सटीक बाइट-दर-बाइट स्ट्रिंग मिलान लागू करना होगा।
- URI क्वेरी पैरामीटर में टोकन पर पूर्ण प्रतिबंध: HTTP एक्सेस लॉग और प्रॉक्सी कैश में टोकन रिसाव को रोकने के लिए टोकन URL में पास नहीं किए जा सकते।
- रिफ्रेश टोकन सुरक्षा अनिवार्य: ऑथराइजेशन सर्वर को या तो रिफ्रेश टोकन रोटेशन (RTR) या सेंडर-कंस्ट्रेंड टोकन (DPoP / mTLS) लागू करना होगा।
आर्किटेक्चरल तुलना: OAuth 1.0a बनाम OAuth 2.0 बनाम OAuth 2.1
| आर्किटेक्चरल आयाम | OAuth 1.0a (RFC 5849) | OAuth 2.0 (RFC 6749 / 6750) | OAuth 2.1 (IETF मानक 2026) |
|---|---|---|---|
| क्रिप्टोग्राफिक मॉडल | एप्लीकेशन-लेयर अनुरोध हस्ताक्षर (HMAC-SHA1/RSA) | ट्रांसपोर्ट लेयर सिक्योरिटी (TLS) + प्लेन बियरर | TLS + अनिवार्य PKCE + सेंडर कंस्ट्रैनिंग (DPoP/mTLS) |
| बियरर टोकन रीप्ले जोखिम | प्रतिरक्षित (अद्वितीय नॉनस के साथ हस्ताक्षरित) | अत्यधिक उच्च (कब्जा = पूर्ण अधिकार) | शमित (DPoP प्रूफ कीज के माध्यम से प्रेषक-बाध्य) |
| PKCE आवश्यकता | समर्थित नहीं | वैकल्पिक (RFC 7636, मुख्य रूप से मोबाइल) | सभी ऑथराइजेशन कोड एक्सचेंज के लिए अनिवार्य |
Implicit Grant (response_type=token) |
समर्थित नहीं | अनुमत (ब्राउज़र SPAs के लिए डिज़ाइन किया गया) | पूरी तरह से हटाया गया और निषिद्ध |
| Password Grant (ROPC) | समर्थित नहीं | अनुमत (लीगेसी डायरेक्ट एक्सचेंज) | पूरी तरह से हटाया गया और निषिद्ध |
| Redirect URI सत्यापन | प्रीफिक्स मिलान अनुमत | वाइल्डकार्ड और पाथ मिलान अक्सर अनुमत | सटीक बाइट-दर-बाइट मिलान अनिवार्य |
| URI क्वेरी में टोकन | समर्थित | अनुमत (?access_token=...) |
सख्ती से निषिद्ध (केवल हेडर या बॉडी) |
| रिफ्रेश टोकन चक्र | कोई नेटिव तंत्र नहीं | निरस्तीकरण या समाप्ति तक एकल टोकन पुन: उपयोग | अनिवार्य रोटेशन (RTR) या क्रिप्टोग्राफिक बाइंडिंग |
| लोकल CLI एजेंट्स उपयुक्तता | बहुत खराब (शेल में भंगुर हस्ताक्षर) | कमजोर (लूपबैक रीडायरेक्ट का अवरोधन) | इष्टतम (PKCE + लूपबैक अल्पकालिक पोर्ट्स) |
| रिमोट MCP सर्वर उपयुक्तता | स्ट्रीमिंग JSON-RPC के साथ असंगत | उपयोग योग्य लेकिन सीक्रेट लीक का उच्च जोखिम | डिफ़ॉल्ट मानक (सख्त न्यूनतम विशेषाधिकार) |
3. मॉडल कॉन्टेक्स्ट प्रोटोकॉल (MCP) ऑथ टोपोलॉजी: एजेंट-टू-सर्वर संचार सुरक्षा
एंथ्रोपिक द्वारा ओपन-सोर्स किया गया और Claude Code, Cursor, Windsurf में अपनाया गया मॉडल कॉन्टेक्स्ट प्रोटोकॉल (MCP), JSON-RPC 2.0 पर एक असममित क्लाइंट-सर्वर आर्किटेक्चर स्थापित करता है।
MCP परिनियोजन में दो अलग-अलग संचार सीमाएं शामिल हैं:
- सीमा A (होस्ट से MCP सर्वर): LLM क्लाइंट एप्लिकेशन (Claude Code, Cursor) और MCP सर्वर प्रोसेस के बीच का कनेक्शन।
- सीमा B (MCP सर्वर से अपस्ट्रीम एंटरप्राइज इंफ्रास्ट्रक्चर): MCP सर्वर और बाहरी SaaS API (GitHub, Linear, Jira, Slack) के बीच का कनेक्शन।
मॉडल कॉन्टेक्स्ट प्रोटोकॉल (MCP) ऑथेंटिकेशन टोपोलॉजी:
+-------------------------------------------------------------------------------------------------------+
| MCP होस्ट रनटाइम (जैसे Claude Code / Cursor / स्वायत्त एजेंट हार्नेस) |
| |
| +---------------------+ प्रॉम्प्ट कॉन्टेक्स्ट +--------------------------------------------+ |
| | यूजर प्रॉम्प्ट / LLM | <───────────────────────────> | LLM रीजनिंग इंजन (Claude 3.7 / GPT-4o) | |
| +----------+----------+ +--------------------------------------------+ |
| | टूल कॉल प्रेषित करता है (`tools/call`) |
| v |
| +--------------------------------------------------------------------------------------------------+ |
| | MCP क्लाइंट इंजन | |
| | - ऑथ सर्वर के साथ OAuth 2.1 PKCE हैंडशेक प्रबंधित करता है | |
| | - गैर-निर्यात योग्य मेमोरी में अल्पकालिक DPoP प्राइवेट की रखता है | |
| | - प्रति-अनुरोध DPoP Proof JWT बनाता है; JSON-RPC हेडर में एक्सेस टोकन इंजेक्ट करता है | |
| +-----------------------------------+--------------------------------------------------------------+ |
+--------------------------------------|----------------------------------------------------------------+
|
| ट्रांसपोर्ट: Stdio (लोकल प्रोसेस) या SSE/HTTP (रिमोट सर्वर)
v
+-------------------------------------------------------------------------------------------------------+
| MCP सर्वर रनटाइम (जैसे GitHub MCP / एंटरप्राइज डेटाबेस MCP) |
| |
| +--------------------------------------------------------------------------------------------------+ |
| | ऑथेंटिकेशन और टोकन सत्यापन इंटरसेप्टर | |
| | 1. ऑथराइजेशन सर्वर JWKS के माध्यम से OAuth 2.1 टोकन हस्ताक्षर की पुष्टि करता है | |
| | 2. DPoP Proof सत्यापित करता है: HTTP विधि, URI, Nonce और पब्लिक की की जांच करता है | |
| | 3. स्कोप्स का मूल्यांकन करता है: न्यूनतम विशेषाधिकार लागू करता है (`issues:read` vs `admin:all`) | |
| +-----------------------------------+--------------------------------------------------------------+ |
| | |
| v |
| +--------------------------------------------------------------------------------------------------+ |
| | MCP टूल निष्पादन इंजन (`tools/call` कार्यान्वयन) | |
| | - इनपुट को सैनिटाइज करता है, पाथ ट्रैवर्सल रोकता है, सैंडबॉक्स में API कॉल करता है | |
| +-----------------------------------+--------------------------------------------------------------+ |
+--------------------------------------|----------------------------------------------------------------+
| अपस्ट्रीम API कॉल (स्कोप्ड डेलिगेटेड टोकन के साथ प्रमाणित)
v
+----------------------------------+
| अपस्ट्रीम एंटरप्राइज SaaS / DB |
| (GitHub / Jira / PostgreSQL / S3)|
+----------------------------------+
Stdio बनाम रिमोट SSE/HTTP ट्रांसपोर्ट की तुलना
- लोकल Stdio ट्रांसपोर्ट (
transport: "stdio"):
- MCP सर्वर होस्ट द्वारा शुरू की गई स्थानीय चाइल्ड प्रोसेस के रूप में चलता है, जो मानक इनपुट और आउटपुट पर संचार करता है।
- सुरक्षा एंटीপैटर्न: ऐतिहासिक रूप से, डेवलपर्स एनवायरनमेंट वेरिएबल्स के जरिए क्रेडेंशियल्स पास करते थे:
- भेद्यता: एजेंट द्वारा निष्पादित कोई भी शेल कमांड या कंटेनर में चलने वाली कोई भी सबप्रोसेस
/proc/[pid]/environका निरीक्षण कर सकती है याenvचला सकती है, जिससे संगठन का संपूर्ण GitHub एक्सेस तुरंत चोरी हो सकता है। - OAuth 2.1 समाधान: होस्ट एक OAuth 2.1 PKCE टोकन वॉल्ट का प्रबंधन करता है। MCP सर्वर बिना किसी स्टेटिक सीक्रेट के शुरू होता है और हैंडशेक के दौरान अल्पकालिक टोकन प्राप्त करता है।
- रिमोट SSE/HTTP ट्रांसपोर्ट (
transport: "sse"):
- MCP सर्वर एक HTTP पोर्ट पर सुनने वाली वितरित वेब सेवा के रूप में कार्य करता है, जो सर्वर-टू-क्लाइंट संचार के लिए Server-Sent Events का उपयोग करता है।
- इस आर्किटेक्चर में OAuth 2.1 अनिवार्य है। MCP क्लाइंट को HTTP
Authorizationहेडर का उपयोग करके प्रमाणित होना चाहिए, जो JWKS और DPoP प्रूफ से सुरक्षित होता है।
4. PKCE (RFC 7636) का गहन विश्लेषण: एजेंट लोकल कॉलबैक की सुरक्षा
Proof Key for Code Exchange (PKCE) मूल रूप से मोबाइल उपकरणों पर ऑथराइजेशन कोड अवरोधन हमलों को रोकने के लिए RFC 7636 में मानकीकृत किया गया था। OAuth 2.1 के तहत, PKCE प्रत्येक ऑथराइजेशन कोड एक्सचेंज के लिए अनिवार्य है।
CLI एजेंट्स और IDE पब्लिक क्लाइंट्स क्यों हैं
Claude Code, Cursor और Roo Code जैसे AI टूल्स को OAuth आर्किटेक्चर के तहत पब्लिक क्लाइंट्स (Public Clients) के रूप में वर्गीकृत किया गया है। चूंकि उनका सोर्स कोड या बाइनरी पूरी तरह से उपयोगकर्ता की स्थानीय मशीन पर चलता है, वे सुरक्षित रूप से स्टेटिक client_secret संग्रहीत नहीं कर सकते। यदि कोई डेवलपर ओपन-सोर्स CLI एजेंट में क्लाइंट सीक्रेट एम्बेड करता है, तो कोई भी बाइनरी को डिकंपाइल करके सीक्रेट निकाल सकता है।
जब कोई पब्लिक क्लाइंट ऑथराइजेशन का अनुरोध करता है, तो सर्वर एक स्थानीय रीडायरेक्ट URI (आमतौर पर एक अस्थायी लूपबैक HTTP सर्वर जैसे http://127.0.0.1:18492/callback) के माध्यम से ऑथराइजेशन कोड लौटाता है।
ऑथराइजेशन कोड अवरोधन हमला (PKCE के बिना):
1. वैध एजेंट CLI ऑथ सर्वर से ऑथ कोड का अनुरोध करता है।
2. डेवलपर मशीन पर दुर्भावनापूर्ण बैकग्राउंड प्रोसेस लोकल पोर्ट को सुनती है।
3. ऑथ सर्वर ब्राउज़र को http://127.0.0.1:18492/callback?code=AUTH_CODE_123 पर रीडायरेक्ट करता है।
4. दुर्भावनापूर्ण प्रोसेस AUTH_CODE_123 को इंटरसेप्ट कर लेती है।
5. दुर्भावनापूर्ण प्रोसेस /oauth/token पर AUTH_CODE_123 पोस्ट करती है।
चूंकि क्लाइंट पब्लिक है (client_secret की आवश्यकता नहीं), ऑथ सर्वर हमलावर को Access Token दे देता है!
PKCE का गणितीय रक्षा तंत्र
PKCE प्रत्येक व्यक्तिगत ऑथराइजेशन अनुरोध के लिए गतिशील रूप से उत्पन्न वन-टाइम क्रिप्टोग्राफिक सीक्रेट पेश करके इस भेद्यता को समाप्त करता है।
PKCE प्रोटोकॉल वायर फ्लो:
+-------------+ +-----------------------+ +--------------------+
| Agent CLI | | यूजर ब्राउज़र | | ऑथ सर्वर |
| (क्लाइंट) | +-----------+-----------+ +---------+----------+
+------+------+ | |
| 1. code_verifier बनाता है (एंट्रॉपी) | |
| code_challenge = S256(...) निकालता | |
| | |
| 2. लूपबैक HTTP लिसनर शुरू करता है | |
| चैलेंज के साथ ब्राउज़र खोलता है ───>| 3. GET /authorize?response_type=code |
| | &client_id=agent_cli |
| | &code_challenge=E9Melhoa2Owv... |
| | &code_challenge_method=S256 ─────────>|
| | | 4. यूजर सहमति।
| | 5. 302 लोकल लूपबैक पर रीडायरेक्ट | चैलेंज स्टोर हुआ
| |<─────────────────────────────────────────|
|<───────────────────────────────────────| http://127.0.0.1:18492/callback?code=AC_88921
| 6. कोड के साथ कॉलबैक पकड़ता है |
| |
| 7. POST /oauth/token |
| code=AC_88921 & code_verifier=dBjftJeZ4CVP-mB92K... ─────────────────────────>|
| | 8. गणना व मिलान:
| | SHA256(verifier)
| | == स्टोर चैलेंज?
| 9. Access Token + Refresh Token (RTR) लौटाता है <─────────────────────────────────| हाँ: टोकन जारी
+------+------+
- Code Verifier: AI एजेंट असंग्रहीत URL वर्णों (
[A-Z],[a-z],[0-9],-,.,_,~) का उपयोग करके 43 से 128 वर्णों की उच्च-एंट्रॉपी रैंडम स्ट्रिंग $V$ बनाता है: - Code Challenge: क्लाइंट $V$ के SHA-256 हैश की गणना करता है और इसे बिना पैडिंग के Base64URL एन्कोड करता है:
- ऑथराइजेशन अनुरोध: क्लाइंट
/authorizeपर $C$ औरcode_challenge_method=S256भेजता है। सर्वर $C$ को सुरक्षित रखता है। - टोकन एक्सचेंज: क्लाइंट
/tokenपर कच्चाcode_verifier=Vभेजता है। सर्वर गणना करता है और सत्यापित करता है कि $\text{Base64URL-Encode}(\text{SHA-256}(V)) == C$ है।
भले ही कोई दुर्भावनापूर्ण प्रोग्राम कोड को पकड़ ले, वह इसे टोकन के लिए नहीं बदल सकता क्योंकि उसके पास मूल code_verifier नहीं है।
प्रोडक्शन TypeScript कार्यान्वयन: हार्डन्ड PKCE इंजन
// pkce.ts - Enterprise OAuth 2.1 PKCE Engine for AI Agent Clients
import { randomBytes, createHash } from "node:crypto";
export interface PKCEChallenge {
codeVerifier: string;
codeChallenge: string;
codeChallengeMethod: "S256";
}
export class PKCEEngine {
/**
* Generates a cryptographically secure code_verifier (RFC 7636 Section 4.1)
* Length defaults to 64 bytes of entropy (yielding ~86 base64url characters).
*/
public static generateVerifier(length: number = 64): string {
if (length < 32 || length > 96) {
throw new RangeError("Verifier byte length must be between 32 and 96.");
}
const buffer = randomBytes(length);
return this.base64UrlEncode(buffer);
}
/**
* Computes the S256 code_challenge from the code_verifier (RFC 7636 Section 4.2)
*/
public static computeChallenge(verifier: string): string {
const hash = createHash("sha256").update(verifier, "ascii").digest();
return this.base64UrlEncode(hash);
}
/**
* Generates the complete PKCE pair ready for OAuth 2.1 authorization
*/
public static createPair(): PKCEChallenge {
const codeVerifier = this.generateVerifier(64);
const codeChallenge = this.computeChallenge(codeVerifier);
return {
codeVerifier,
codeChallenge,
codeChallengeMethod: "S256",
};
}
/**
* Server-side verification: Validates an incoming code_verifier against stored challenge
*/
public static verify(verifier: string, storedChallenge: string): boolean {
const computed = this.computeChallenge(verifier);
// Timing-safe buffer comparison to prevent side-channel timing attacks
const bufA = Buffer.from(computed);
const bufB = Buffer.from(storedChallenge);
if (bufA.length !== bufB.length) return false;
let result = 0;
for (let i = 0; i < bufA.length; i++) {
result |= bufA[i] ^ bufB[i];
}
return result === 0;
}
private static base64UrlEncode(buffer: Buffer): string {
return buffer
.toString("base64")
.replace(/\\+/g, "-")
.replace(/\\//g, "_")
.replace(/=+$/, "");
}
}
5. हेडलेस सर्वर और CLI ऑथराइजेशन: डिवाइस फ्लो (RFC 8628)
PKCE डेस्कटॉप वातावरण में काम करता है, लेकिन आधुनिक AI एजेंट तेजी से बिना ब्राउज़र वाले हेडलेस वातावरण में चलते हैं:
- क्लाउड क्लस्टर में डॉकर कंटेनर (AWS ECS, Kubernetes, Fly.io)।
- अल्पकालिक CI/CD रनर्स (GitHub Actions, GitLab CI)।
- रिमोट वर्चुअल मशीन और टर्मिनल SSH सत्र।
हेडलेस वातावरण में ब्राउज़र नहीं खोला जा सकता, और टर्मिनल में पासवर्ड पूछना OAuth 2.1 का उल्लंघन है। इसका मानक समाधान OAuth 2.0 Device Authorization Grant (RFC 8628) है:
हेडलेस एजेंट रनटाइम में डिवाइस ऑथराइजेशन ग्रांट (RFC 8628):
+-------------------+ +-----------------------+
| हेडलेस एजेंट | | ऑथ सर्वर |
| (Docker / Cloud) | +-----------+-----------+
+---------+---------+ |
| 1. POST /oauth/device/code (client_id, scope) ──────────────────────>|
| | 2. उत्पन्न करता है:
| 3. डिवाइस क्रेडेंशियल लौटाता है: | device_code (गुप्त)
| - user_code: "WDJB-HGNP" | user_code (सार्वजनिक)
| - verification_uri: "https://auth.corp.com/activate" | interval: 5 सेकंड
| - interval: 5 <───────────────────────────────────────────────────|
| |
| 4. टर्मिनल पर निर्देश प्रदर्शित करता है: |
| "https://auth.corp.com/activate खोलें और कोड दर्ज करें: WDJB-HGNP"|
| |
| 5. पोलिंग लूप शुरू करता है: |
| POST /oauth/token (grant_type=device_code, device_code=...) ─────>|
| <── 400 Bad Request: {"error": "authorization_pending"} ─────────|
| [5 सेकंड प्रतीक्षा करता है] |
| |
+---------+---------+ उपयोगकर्ता लैपटॉप या मोबाइल पर URL खोलता है |
| यूजर लैपटॉप | ──> "WDJB-HGNP" दर्ज करता है, MFA पूरा करता है ───────────>| 6. ऑथराइजेशन स्वीकृत!
+-------------------+ |
| |
| 7. अगला पोल चक्र: |
| POST /oauth/token ───────────────────────────────────────────────>|
| <── 200 OK: {access_token: "...", refresh_token: "..."} ──────────|
v
[हेडलेस एजेंट बिना पासवर्ड एक्सपोज़र के सुरक्षित रूप से प्रमाणित]
मशीन-टू-मशीन (M2M) विकल्प: RFC 7523 प्राइवेट की JWT
जब कोई स्वायत्त AI एजेंट बिना किसी मानवीय हस्तक्षेप के पूरी तरह से स्वचालित रूप से काम करता है (उदा. रात्रिकालीन कोड रिफैक्टरिंग बॉट), तो डिवाइस फ्लो भी अनुपयुक्त हो जाता है।
ऐसी स्थिति में, जीरो-ट्रस्ट आर्किटेक्चर RFC 7523 (क्लाइंट प्रमाणीकरण के लिए JWT प्रोफ़ाइल) द्वारा समर्थित Client Credentials Grant का उपयोग करता है:
- नेटवर्क पर स्टेटिक
client_secretप्रसारित करने के बजाय, एजेंट के पास HSM या कुबेरनेट्स सीक्रेट्स में सुरक्षित रूप से माउंट की गई एक असममित प्राइवेट की (RSA या ECDSA) होती है। - ऑथेंटिकेशन के समय एजेंट 60 सेकंड की वैधता और अद्वितीय UUID
jtiवाला एक अल्पकालिक JWT साइन करके भेजता है। - ऑथराइजेशन सर्वर एजेंट की पूर्व-पंजीकृत पब्लिक की के विरुद्ध हस्ताक्षर की पुष्टि करता है।
6. टोकन लाइफसाइकिल और स्वायत्त रिफ्रेश वर्कफ्लो
स्वायत्त AI एजेंट अक्सर कई घंटों तक चलने वाले वर्कफ्लो निष्पादित करते हैं। चूंकि जोखिम कम करने के लिए OAuth 2.1 एक्सेस टोकन जानबूझकर अल्पकालिक (आमतौर पर 5 से 15 मिनट) बनाए जाते हैं, एजेंट को सक्रिय टूल कॉल्स को बाधित किए बिना स्वायत्त रूप से टोकन का नवीनीकरण करना चाहिए।
रिफ्रेश टोकन रोटेशन (RTR) और ब्रीच डिटेक्शन
OAuth 2.1 के तहत रिफ्रेश टोकन को रिफ्रेश टोकन रोटेशन (Refresh Token Rotation, RTR) द्वारा सुरक्षित किया जाता है:
- हर बार जब एजेंट
/oauth/tokenपरrefresh_tokenसबमिट करता है, तो सर्वर उस टोकन को तुरंत अमान्य कर देता है। - सर्वर एक नया
access_tokenऔर एक नयाrefresh_tokenजारी करता है। - यदि कोई हमलावर पुराने अप्रचलित टोकन का पुन: उपयोग करने का प्रयास करता है, तो सर्वर इसे तत्काल समझौता घटना मानता है:
$$\text{Incoming Token State} == \text{"REVOKED"} \implies \text{Revoke All Tokens in Family Tree}$$
सर्वर तुरंत उस ग्रांट फैमिली से संबंधित सभी सक्रिय एक्सेस और रिफ्रेश टोकन रद्द कर देता है।
रिफ्रेश टोकन रोटेशन (RTR) और समझौता रिकवरी:
टोकन निर्माण श्रृंखला:
[Refresh Token A] ──(प्रयुक्त)──> [Refresh Token B] ──(प्रयुक्त)──> [Refresh Token C] (सक्रिय)
│
│ हमलावर पुराने [Refresh Token A] का पुन: उपयोग करने की कोशिश करता है
v
[ऑथराइजेशन सर्वर निरस्त टोकन A के पुन: उपयोग का पता लगाता है!]
│
▼
[गंभीर सुरक्षा चेतावनी]: टोकन B, टोकन C और सभी संबंधित एक्सेस टोकन तुरंत रद्द।
एजेंट सत्र सुरक्षित रूप से समाप्त होता है, अनधिकृत विशेषाधिकार विस्तार रुक जाता है।
पायथन प्रोडक्शन कार्यान्वयन: थ्रेड-सेफ एसिंक्रोनस टोकन मैनेजर
मल्टी-एजेंट सिस्टम में जब 10 पैरेलल सब-एजेंट एक ही MCP सर्वर को कॉल करते हैं, तो कई अनुरोध एक साथ टोकन समाप्ति का पता लगा सकते हैं। यदि सभी 10 एक साथ रिफ्रेश करने का प्रयास करते हैं, तो 9 विफल हो जाएंगे। निम्नलिखित पायथन मॉड्यूल म्यूटेक्स लॉक के साथ टोकन प्रबंधन प्रदान करता है:
# token_manager.py - Enterprise Async Token Lifecycle Manager for AI Agents
import asyncio
import time
import httpx
from typing import Optional, Dict, Any
class AgentTokenManager:
def __init__(
self,
token_endpoint: str,
client_id: str,
initial_refresh_token: str,
proactive_refresh_seconds: int = 60,
):
self.token_endpoint = token_endpoint
self.client_id = client_id
self.refresh_token = initial_refresh_token
self.access_token: Optional[str] = None
self.expires_at: float = 0.0
self.proactive_refresh_seconds = proactive_refresh_seconds
self._lock = asyncio.Lock()
async def get_valid_access_token(self) -> str:
now = time.time()
if self.access_token and (self.expires_at - now) > self.proactive_refresh_seconds:
return self.access_token
async with self._lock:
now = time.time()
if self.access_token and (self.expires_at - now) > self.proactive_refresh_seconds:
return self.access_token
await self._refresh_token_exchange()
if not self.access_token:
raise RuntimeError("Failed to acquire valid access token from authorization server.")
return self.access_token
async def _refresh_token_exchange(self) -> None:
payload = {
"grant_type": "refresh_token",
"refresh_token": self.refresh_token,
"client_id": self.client_id,
}
async with httpx.AsyncClient(timeout=10.0) as client:
try:
response = await client.post(
self.token_endpoint,
data=payload,
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
except httpx.RequestError as exc:
raise ConnectionError(f"Network transport error during token refresh: {exc}")
if response.status_code == 200:
data: Dict[str, Any] = response.json()
self.access_token = data["access_token"]
expires_in = int(data.get("expires_in", 3600))
self.expires_at = time.time() + expires_in
# Update to the newly rotated refresh token if provided
if "refresh_token" in data:
self.refresh_token = data["refresh_token"]
elif response.status_code in (400, 401):
err_data = response.json()
# If error is 'invalid_grant', the token was likely already rotated or revoked
raise PermissionError(f"Token refresh rejected (possible token theft or expiry): {err_data}")
else:
response.raise_for_status()
7. जीरो-ट्रस्ट क्रेडेंशियल आइसोलेशन: DPoP (RFC 9449) और हार्डवेयर एन्क्लेव
OAuth 2.1 और PKCE के बाद भी पारंपरिक Bearer Tokens में एक गंभीर खामी बनी रहती है: यदि बियरर टोकन चोरी हो जाता है, तो कोई भी उसका उपयोग कर सकता है।
यदि कोई हमलावर इनडायरेक्ट प्रॉम्प्ट इंजेक्शन के जरिए एजेंट से अनधिकृत HTTP कॉल (SSRF) करवाता है, तो बियरर टोकन लीक हो जाता है। वास्तविक जीरो-ट्रस्ट सुरक्षा के लिए OAuth 2.1 DPoP: Demonstrating Proof-of-Possession at the Application Layer (RFC 9449) को शामिल करता है।
DPOP (RFC 9449) एप्लीकेशन-लेयर सेंडर कंस्ट्रैनिंग:
+-------------------------------------------------------------------------------------------------+
| एजेंट स्थानीय परिवेश (क्लाइंट) |
| - अल्पकालिक की-पेयर बनाता है: पब्लिक की (JWK) + प्राइवेट की (केवल RAM/एन्क्लेव में) |
+-------------------------------------------------------------------------------------------------+
│
│ 1. DPoP Proof हेडर संलग्न करता है:
│ DPoP: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Ar...
│ Payload: {
│ "htm": "GET",
│ "htu": "https://api.enterprise.com/mcp/tools",
│ "iat": 1772630400,
│ "jti": "random_nonce_9921",
│ "jwk": { ...public_key... }
│ }
│
│ 2. बाउंड DPoP टोकन भेजता है:
│ Authorization: DPoP dpop_access_token_88921
v
+-------------------------------------------------------------------------------------------------+
| एंटरप्राइज MCP गेटवे (रिसोर्स सर्वर) |
| 1. सत्यापित करता है कि एक्सेस टोकन JWK में पब्लिक की फिंगरप्रिंट से बंधा है। |
| 2. सत्यापित करता है कि DPoP Proof हस्ताक्षर पब्लिक की से मेल खाता है। |
| 3. पुष्टि करता है कि "htm" = "GET" है और "htu" सटीक गंतव्य URL से मेल खाता है। |
| 4. जांचता है कि टाइमस्टैम्प "iat" 60 सेकंड के भीतर है और "jti" पहले उपयोग नहीं हुआ है। |
+-------------------------------------------------------------------------------------------------+
│
┌────────────────────────────────────────┴────────────────────────────────────────┐
▼ ▼
[वैध प्रमाण और मेल खाती कुंजी] [चोरी किए गए टोकन का रीप्ले प्रयास]
अनुरोध टूल निष्पादन के लिए आगे बढ़ता है हमलावर के पास टोकन है, लेकिन एजेंट की
लोकल प्राइवेट की नहीं है।
परिणाम: 401 Unauthorized अवरोध!
DPoP व्यवहार में कैसे काम करता है
- अल्पकालिक कुंजी निर्माण: एजेंट सत्र शुरू होने पर मेमोरी में एक असममित कुंजी युग्म (ECDSA P-256) उत्पन्न करता है।
- क्रिप्टोग्राफिक बाइंडिंग: ऑथराइजेशन सर्वर द्वारा जारी किए गए एक्सेस टोकन में पब्लिक की का थंबप्रिंट (
jkt) शामिल होता है। - प्रति-अनुरोध अधिकार प्रमाण: हर अनुरोध के साथ एजेंट HTTP विधि, सटीक URI, टाइमस्टैम्प और UUID युक्त एक वन-टाइम DPoP JWT पर हस्ताक्षर करता है।
- गहन सुरक्षा: भले ही टोकन स्ट्रिंग लीक हो जाए, एजेंट की प्राइवेट की के बिना हमलावर टोकन का उपयोग नहीं कर सकता।
8. एंटरप्राइज सुरक्षा बेंचमार्क, जोखिम मैट्रिक्स और विफलता मोड
अनुभवजन्य प्रदर्शन बेंचमार्क (10,000 पुनरावृत्तियां, Apple M4 Max हार्डवेयर)
| प्रमाणीकरण आर्किटेक्चर | क्लाइंट हैंडशेक लेटेंसी (p50) | क्लाइंट हैंडशेक लेटेंसी (p99) | प्रति-अनुरोध सत्यापन ओवरहेड | रीप्ले सुरक्षा | क्लाइंट मेमोरी फुटप्रिंट | सर्वर CPU ओवरहेड |
|---|---|---|---|---|---|---|
| स्टेटिक PAT / API की | 0.1 ms (कोई हैंडशेक नहीं) | 0.2 ms | 0.02 ms (स्ट्रिंग मिलान) | शून्य (पूर्ण रीप्ले) | < 1 KB | बेसलाइन |
| OAuth 1.0a (HMAC-SHA1) | 14.2 ms | 38.5 ms | 1.84 ms (हस्ताक्षर पार्सिंग) | आंशिक (नॉन्स चेक) | 12 KB | +18% |
| OAuth 2.0 Bearer | 45.1 ms | 112.0 ms | 0.15 ms (JWT हस्ताक्षर/कैश) | शून्य (बियरर रीप्ले) | 18 KB | +4% |
| OAuth 2.1 (PKCE + RTR) | 48.6 ms | 118.4 ms | 0.16 ms (JWT सत्यापन) | मध्यम (RTR निरस्तीकरण) | 24 KB | +5% |
| OAuth 2.1 + DPoP (P-256) | 54.2 ms | 132.8 ms | 1.22 ms (DPoP सत्यापन) | अधिकतम (जीरो रीप्ले) | 36 KB | +12% |
| mTLS (RFC 8705) | 62.8 ms | 154.1 ms | 0.45 ms (TLS सत्र कैश) | अधिकतम (प्रमाणपत्र बाध्य) | 128 KB | +15% |
एंटरप्राइज एजेंट खतरा जोखिम मैट्रिक्स
खतरे की गंभीरता बनाम प्रोटोकॉल शमन:
+-------------------------------+-------------------+-------------------+-------------------+-------------------+
| हमला वेक्टर | स्टेटिक API कीज | OAuth 1.0a | OAuth 2.0 Bearer | OAuth 2.1 + DPoP |
+-------------------------------+-------------------+-------------------+-------------------+-------------------+
| 1. अप्रत्यक्ष प्रॉम्प्ट इंजेक्शन| गंभीर (10/10) | उच्च (7/10) | गंभीर (10/10) | कम (2/10) |
| (Env Var / लॉग रिसाव) | मुख्य कीज लीक | हस्ताक्षर जटिलता | बियरर टोकन चोरी | बिना कुंजी टोकन व्यर्थ|
+-------------------------------+-------------------+-------------------+-------------------+-------------------+
| 2. लोकल पोर्ट स्निफिंग | N/A | कम (3/10) | उच्च (8/10) | सुरक्षित (1/10) |
| (CLI लूपबैक इंटरसेप्शन) | कोई रीडायरेक्ट नहीं| नॉनस हस्ताक्षरित | ऑथ कोड चोरी | PKCE द्वारा अवरुद्ध|
+-------------------------------+-------------------+-------------------+-------------------+-------------------+
| 3. SSRF टूल पिवट हमला | गंभीर (10/10) | मध्यम (5/10) | गंभीर (10/10) | सुरक्षित (1/10) |
| (अनधिकृत सर्वर कॉल) | क्रेडेंशियल लीक | URI विफलता | बियरर पुन: उपयोग | DPoP URI बेमेल |
+-------------------------------+-------------------+-------------------+-------------------+-------------------+
| 4. सबप्रोसेस स्नूपिंग | गंभीर (10/10) | मध्यम (5/10) | उच्च (8/10) | कम (2/10) |
| (/proc/environ का निरीक्षण)| स्थायी रूप से खुला| Env में कीज मौजूद | Env में बियरर | अल्पकालिक/बाध्य |
+-------------------------------+-------------------+-------------------+-------------------+-------------------+
| 5. रिफ्रेश रेस कंडीशन | N/A | N/A | कम (2/10) | उच्च (म्यूटेक्स |
| (समानांतर एजेंट समूह) | कोई रिफ्रेश नहीं | कोई रिफ्रेश नहीं | टोकन टकराव | मैनेजर आवश्यक) |
+-------------------------------+-------------------+-------------------+-------------------+-------------------+
9. चरण-दर-चरण कार्यान्वयन गाइड: सुरक्षित OAuth 2.1 + PKCE MCP सर्वर
// server.ts - Hardened Remote MCP Server with OAuth 2.1 Validation
import express, { Request, Response, NextFunction } from "express";
import { createRemoteJWKSet, jwtVerify } from "jose";
const app = express();
app.use(express.json());
// Configuration
const ISSUER = "https://auth.enterprise.com/";
const AUDIENCE = "https://mcp.enterprise.com/";
const JWKS_URI = new URL("https://auth.enterprise.com/.well-known/jwks.json");
const JWKS = createRemoteJWKSet(JWKS_URI);
interface AuthenticatedRequest extends Request {
tokenClaims?: any;
}
/**
* Enterprise OAuth 2.1 Token Validation Middleware
*/
async function requireOAuth21(
req: AuthenticatedRequest,
res: Response,
next: NextFunction
): Promise<void> {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith("Bearer ")) {
res.status(401).json({
jsonrpc: "2.0",
error: { code: -32001, message: "Missing or invalid OAuth 2.1 Authorization header." },
id: req.body?.id || null,
});
return;
}
const token = authHeader.split(" ")[1];
try {
// Cryptographically verify token signature, issuer, audience, and expiration
const { payload } = await jwtVerify(token, JWKS, {
issuer: ISSUER,
audience: AUDIENCE,
});
// Enforce OAuth 2.1 requirement: reject tokens without an expiration claim
if (!payload.exp || typeof payload.exp !== "number") {
res.status(401).json({
jsonrpc: "2.0",
error: { code: -32002, message: "Non-compliant token: missing expiration claim." },
id: req.body?.id || null,
});
return;
}
req.tokenClaims = payload;
next();
} catch (err: any) {
res.status(401).json({
jsonrpc: "2.0",
error: { code: -32003, message: `Token verification failed: ${err.message}` },
id: req.body?.id || null,
});
}
}
/**
* Fine-Grained Scope Enforcement Guard
*/
function requireScope(requiredScope: string) {
return (req: AuthenticatedRequest, res: Response, next: NextFunction): void => {
const scopes: string[] = (req.tokenClaims?.scope || "").split(" ");
if (!scopes.includes(requiredScope)) {
res.status(403).json({
jsonrpc: "2.0",
error: {
code: -32004,
message: `Insufficient permissions: missing required scope '${requiredScope}'`,
},
id: req.body?.id || null,
});
return;
}
next();
};
}
/**
* Standard MCP JSON-RPC 2.0 Handler Endpoint
*/
app.post(
"/mcp/v1",
requireOAuth21,
requireScope("mcp:tools:execute"),
async (req: AuthenticatedRequest, res: Response): Promise<void> => {
const { jsonrpc, method, params, id } = req.body;
if (jsonrpc !== "2.0") {
res.status(400).json({ jsonrpc: "2.0", error: { code: -32600, message: "Invalid JSON-RPC version." }, id });
return;
}
// Router for MCP Primitives
switch (method) {
case "tools/list":
res.json({
jsonrpc: "2.0",
result: {
tools: [
{
name: "query_database",
description: "Executes read-only SQL queries against the analytics warehouse.",
inputSchema: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
],
},
id,
});
break;
case "tools/call":
if (params?.name === "query_database") {
// Verify elevated data scope for this specific tool execution
const scopes: string[] = (req.tokenClaims?.scope || "").split(" ");
if (!scopes.includes("db:analytics:read")) {
res.json({
jsonrpc: "2.0",
error: { code: -32005, message: "Forbidden: tool requires 'db:analytics:read' scope." },
id,
});
return;
}
// Execute tool with verified, scoped identity
const userSub = req.tokenClaims.sub;
console.log(`Executing query on behalf of verified agent identity: ${userSub}`);
res.json({
jsonrpc: "2.0",
result: {
content: [
{
type: "text",
text: JSON.stringify({ status: "success", rows_returned: 42, latency_ms: 12 }),
},
],
},
id,
});
} else {
res.status(404).json({ jsonrpc: "2.0", error: { code: -32601, message: "Tool not found." }, id });
}
break;
default:
res.status(404).json({ jsonrpc: "2.0", error: { code: -32601, message: "Method not found." }, id });
}
}
);
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Hardened OAuth 2.1 MCP Server listening on port ${PORT}`);
});
10. निष्कर्ष और रणनीतिक सिफारिशें (E-E-A-T)
एंटरप्राइज इंफ्रास्ट्रक्चर से स्वायत्त AI मॉडल को कनेक्ट करते समय AI एजेंट्स को अर्ध-विश्वसनीय प्रत्यायोजित कर्ता (Semi-Trusted Delegated Actor) माना जाना चाहिए। किसी एजेंट को पूरी तरह से विश्वसनीय आंतरिक माइक्रोसर्विस मानना या पूरी तरह से अविश्वासनीय बाहरी एजेंट मानना दोनों ही एक वास्तुशिल्प विफलता है।
OAuth 2.1 इस अंतर को पाटने के लिए सटीक क्रिप्टोग्राफिक ढांचा प्रदान करता है, जो स्वायत्तता और एंटरप्राइज जीरो-ट्रस्ट अनुपालन दोनों सुनिश्चित करता है।
AI सुरक्षा आर्किटेक्चर चेकलिस्ट: 5 प्रमुख बिंदु
- सभी स्टेटिक परिवेशी सीक्रेट्स को हटाएं: MCP कॉन्फ़िगरेशन और
.envफ़ाइलों का ऑडिट करें। स्टेटिक PAT को अल्पकालिक OAuth 2.1 एक्सेस टोकन से बदलें। - S256 के साथ PKCE अनिवार्य करें: सुनिश्चित करें कि सभी CLI टूल्स उच्च-एंट्रॉपी SHA-256 के साथ RFC 7636 लागू करें।
- हेडलेस परिवेश को RFC 8628 या प्राइवेट की JWT पर माइग्रेट करें: टर्मिनल पासवर्ड प्रॉम्प्ट हटाकर डिवाइस फ्लो या RFC 7523 का उपयोग करें।
- म्यूटेक्स-लॉक्ड रिफ्रेश टोकन रोटेशन लागू करें: समानांतर एजेंट्स के बीच टकराव से बचने के लिए टोकन रिफ्रेश को समन्वित करें।
- DPoP (RFC 9449) सेंडर-कंस्ट्रैन्ड टोकन अपनाएं: उच्च-जोखिम वाले टूल्स के लिए DPoP अनिवार्य करें ताकि प्रॉम्प्ट इंजेक्शन हमलों को नेटवर्क स्तर पर ही रोका जा सके।