1 पॉइंट द्वारा GN⁺ 4 시간 전 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • कई CLI डिफ़ॉल्ट रूप से localhost OAuth redirect का उपयोग करते हैं, जो लैपटॉप के लोकल ब्राउज़र में जल्दी पूरा हो जाता है, लेकिन SSH·कंटेनर·WSL जैसे डेवलपमेंट एनवायरमेंट में यही धारणा टूट जाती है और login flow रुक जाता है
  • मौजूदा तरीका यह है कि CLI 127.0.0.1 पर एक अस्थायी HTTP server खोलता है, ब्राउज़र को authentication URL पर भेजता है, फिर authentication provider authorization code को local callback पर वापस भेजता है
  • 2019 में standard बना RFC 8628 Device Authorization Grant token मांगने वाले CLI और user के authenticate करने वाले browser device को अलग कर देता है, जिससे port binding या local browser पर निर्भरता खत्म हो जाती है
  • Device flow में device_code, user_code, verification_uri, interval मिलते हैं और /token को समय-समय पर poll किया जाता है, साथ ही authorization_pending, slow_down, access_denied, expired_token जैसी standard states को handle किया जाता है
  • अगर नया CLI बना रहे हैं, तो device flow को default रखना चाहिए, .well-known/openid-configuration से endpoint discover करना चाहिए, और refresh token को ~/.config के JSON file में नहीं बल्कि OS keychain में रखना चाहिए

localhost redirect किन बातों को मानकर चलता है

  • आम CLI login इस धारणा पर काम करता है कि local HTTP server और system browser एक ही मशीन पर हैं
    • CLI 127.0.0.1 के किसी तय port पर HTTP server bind करता है
    • system browser में OAuth authorization endpoint खोलता है और redirect_uri=http://127.0.0.1:<port>/callback शामिल करता है
    • user login करता है तो authentication provider authorization code को loopback URL पर 302 redirect करता है
    • CLI का छोटा HTTP server code पढ़ता है और token endpoint से token के बदले exchange करता है
    • ज़्यादातर मामलों में PKCE भी जुड़ा होता है, और उसके बाद “you may close this tab” पेज दिखता है
  • gcloud auth login, wrangler login, पुराना vercel login और कई vendor CLI यही तरीका इस्तेमाल करते हैं
    • Wrangler 8976 port इस्तेमाल करता है
    • gcloud 8085 इस्तेमाल करता है
    • Claude Code हर run पर अस्थायी port चुनता है
  • RFC 8252 browser मौजूद होने पर native app के लिए इस pattern की सिफारिश करता है, लेकिन host पर browser न हो तो क्या करना है, यह नहीं बताता

user localhost चरण को ठीक से क्यों नहीं देख पाता

  • localhost callback बहुत कम समय के लिए आता है, इसलिए ज़्यादातर users उसे देख ही नहीं पाते
  • CLI जो URL दिखाता है वह लंबा होता है, और उसमें redirect URI query string के अंदर शामिल होता है
  • user authentication provider के असली domain पर login और approval देता है
  • authentication provider browser को localhost callback पर भेजता है, CLI code पढ़ लेता है, फिर polished “signed in” पेज पर आगे बढ़ जाता है
  • ऊपर से देखने पर यह “वेबसाइट पर login किया और CLI authenticate हो गया” जैसा लगता है, लेकिन वास्तव में इस flow को local HTTP server और browser का साथ मौजूद होना संभालता है

SSH·कंटेनर·WSL में यह कहाँ टूटता है

  • पूरा flow इस धारणा पर निर्भर है कि जिस मशीन पर CLI चल रहा है और जिस मशीन पर browser चल रहा है, दोनों एक ही हैं
  • SSH session में remote host पर browser नहीं होता, और xdg-open fail हो सकता है या X forwarding में ऐसा remote browser खुल सकता है जो दिखे ही नहीं
    • callback port को लैपटॉप तक tunnel किया जा सकता है, लेकिन authentication provider में registered redirect URI को tunneled port की अनुमति देनी होगी
  • कंटेनर में browser नहीं होता, और कई images में xdg-open या open भी नहीं होते
    • -p से callback port expose किया जा सकता है, लेकिन पहले यह जानना होगा कि CLI कौन-सा port चुनेगा
    • Cloudflare CLI में इस समस्या से फँसे users की issue लगातार आती रही है
  • WSL में browser Windows पर खुलता है, जबकि loopback server Linux में चलता है
    • WSL2 का port forwarding अक्सर काम करता है, लेकिन हर बार नहीं
  • shared box में उसी मशीन के दूसरे process /proc/net/tcp से listening port ढूँढ सकते हैं, या known port को पहले bind करने की race में आ सकते हैं
    • PKCE code exchange को सुरक्षित करता है, लेकिन redirect के authenticated session को नहीं

fallback खुद design समस्या दिखा देता है

  • जो CLI loopback flow को default देते हैं, वे टूटने की स्थिति के लिए fallback भी साथ रखते हैं
  • gcloud में --no-launch-browser है
  • Wrangler रुक जाता है, और accepted workaround यह है कि दूसरे terminal से localhost URL को सीधे curl किया जाए
  • Anthropic का claude “Paste code here if prompted” प्रिंट करके इंतज़ार करता है
  • ये fallback असल में manual device flow ही हैं, और इसलिए मौजूद हैं क्योंकि CLI जिन environments में वास्तव में इस्तेमाल होता है, वहाँ default flow काम नहीं करता

RFC 8628 Device Authorization Grant

  • RFC 8628 2019 में “input-constrained devices” के लिए आया OAuth 2.0 Device Authorization Grant है
    • इसमें TV, console, CLI शामिल हैं
    • मुख्य विचार यह है कि token मांगने वाली device और user के authenticate करने वाली device को अलग किया जाए
  • CLI authentication provider के device_authorization_endpoint पर POST करता है
    • उदाहरण request client_id=my-cli&scope=openid+offline_access भेजती है
  • authentication provider JSON में ये values लौटाता है
    • device_code
    • user_code
    • verification_uri
    • verification_uri_complete
    • expires_in
    • interval
  • CLI URL और छोटा code दिखाता है, और संभव हो तो verification_uri_complete के लिए QR भी दिखाता है
  • user अपनी पसंद की device पर URL खोलता है, login करता है, फिर requested scope और client name देखकर यह पुष्टि करता है कि वह CLI पर दिख रहे छोटे code से मेल खाता है, और फिर approval देता है

polling और standard state handling

  • CLI हर interval सेकंड में token endpoint को poll करता है
  • grant type urn:ietf:params:oauth:grant-type:device_code होता है
  • RFC 8628 section 3.5 ये states define करता है
    • authorization_pending: user approval का इंतज़ार जारी है
    • slow_down: authentication provider कह रहा है कि polling interval कम बार रखें, और spec के अनुसार interval कम-से-कम 5 सेकंड बढ़ाना चाहिए
    • access_denied: user ने मना कर दिया
    • expired_token: बहुत देर इंतज़ार हुआ और token expire हो गया
  • device flow में CLI कोई port bind नहीं करता और यह नहीं मानता कि execution host पर browser मौजूद होगा
  • यही login तरीका laptop, container और human approval का इंतज़ार कर रही CI job — सभी में काम करता है

polling की लागत और endpoint discovery

  • default polling interval 5 सेकंड है
  • ज़्यादातर authentication 1 मिनट के भीतर पूरी हो जाती है, इसलिए सामान्य login में /token पर लगभग 10 बार polling होती है और फिर रुक जाती है
  • server slow_down के ज़रिए interval बढ़ा सकता है, और अच्छे client को इसका पालन करना चाहिए
  • हर pending login के लिए stateful endpoint पर WebSocket या SSE connection बनाए रखने की तुलना में /token पर stateless polling ज़्यादा सरल और सस्ती है
  • अगर authentication provider OpenID Connect Discovery support करता है, तो CLI .well-known/openid-configuration से device_authorization_endpoint और token_endpoint ले सकता है, जिससे URL hardcode करने की ज़रूरत नहीं रहती

device flow का phishing risk

  • device flow में एक हमला यह है कि attacker असली authentication provider के device_authorization_endpoint को call करके user_code और device_code लेता है, फिर victim को code दर्ज करने के लिए उकसाता है
  • victim असली URL पर, असली code के साथ login कर सकता है और असली consent screen approve कर सकता है
  • attacker अपने बनाए device_code के साथ /token को poll करता रहता है और access token हासिल कर लेता है
  • एक रूसी threat actor ने अगस्त 2024 के बाद M365 tenant को निशाना बनाकर यह campaign चलाया
    • Microsoft Threat Intelligence इसे Storm-2372 के रूप में track करता है
    • Volexity ने इसका attribution APT29/Midnight Blizzard को दिया है
    • कई महाद्वीपों में government, defence और NGO tenant प्रभावित हुए

phishing से बचाव authentication provider की ज़िम्मेदारी है

  • phishing defence CLI की नहीं बल्कि authentication provider की ज़िम्मेदारी होनी चाहिए
  • ज़रूरी mitigations ये हैं
    • user_code की छोटी expiry time
    • verification page पर client name और request origin को साफ़-साफ़ दिखाना
    • code entry attempts पर rate limiting
    • verification_uri_complete न दिखाना ताकि victim लिंक पर click करने के बजाय code खुद दर्ज करे
    • high-value tenant के लिए known network या device न होने पर device code flow रोकने वाली conditional access policy
  • CLI का काम spec का पालन करना है, shortcuts बनाना नहीं
  • device flow local attack surface को social attack surface में बदल देता है, लेकिन अधिक environments में काम करने वाला flow देना और authentication provider की mitigation का लाभ उठाना ज़्यादा उचित है

Go implementation example का मुख्य flow

  • पूरी implementation Go में सिर्फ net/http के साथ लगभग 30 lines में आ जाती है
  • implementation flow इस प्रकार है
    • client_id और scope के साथ DeviceAuthorizationEndpoint पर http.PostForm call
    • response JSON से DeviceCode, UserCode, VerificationURIComplete, Interval decode करना
    • user को VerificationURIComplete और UserCode प्रिंट करना
    • TokenEndpoint पर device_code, client_id, device grant type के साथ बार-बार POST करना
    • authorization_pending हो तो इंतज़ार जारी रखना
    • slow_down हो तो interval 5 सेकंड बढ़ाना
    • error न हो तो access_token और refresh_token लौटाना
    • अन्य error को failure मानना
  • Keycloak realm में “OAuth 2.0 Device Authorization Grant” capability on कर दें, या grant support करने वाला OpenID-certified provider इस्तेमाल करें, तो device-flow login काम करेगा

नए CLI के default के रूप में क्या चुनना चाहिए

  • default device flow होना चाहिए
  • .well-known/openid-configuration से endpoint discover करने चाहिए, URL hardcode नहीं करने चाहिए
  • interval और slow_down का पालन अनिवार्य रूप से करना चाहिए
  • refresh token को ~/.config के नीचे JSON file में नहीं बल्कि OS keychain में रखना चाहिए
  • अगर तेज़ laptop login के लिए loopback path देना ही हो, तो उसे --web flag के पीछे रखें, default न बनाएं

जो CLI आगे बढ़ चुके हैं और जो अभी बाकी हैं

  • कुछ CLI पहले से device flow को default के रूप में इस्तेमाल कर रहे हैं
    • gh auth login शुरू से device flow इस्तेमाल करता आया है, और open source में इसे सबसे साफ़ reference implementation माना जाता है
    • aws sso login IAM Identity Center के साथ end-to-end device flow चलाता है
    • vercel login ने सितंबर 2025 में RFC 8628 पर migration किया, और email-based login व पुराने --oob flag को replace किया
    • Stripe CLI RFC 8628 खुद नहीं है, लेकिन बेहतरीन UX वाला pairing-code flow इस्तेमाल करता है
  • कुछ tools अब भी loopback flow को default रखते हैं और उसके साथ paste-the-code fallback जोड़ते हैं
    • Google gcloud
    • Cloudflare wrangler
    • Anthropic claude
  • अगर किसी CLI को laptop से बाहर जाते ही manual paste-the-code fallback चाहिए, तो बेहतर है कि उसी fallback को default flow बना दिया जाए

1 टिप्पणियां

 
GN⁺ 4 시간 전
Lobste.rs की राय
  • अभिव्यक्ति थोड़ी ढीली-ढाली है, लेकिन दिलचस्प है। device code/link को हर 1 मिनट में बदलने से phishing में उसके दुरुपयोग की संभावना भी कम हो सकती है
    एक बार इस्तेमाल होने के बाद rotation रोक दी जाए और उस session को IP या browser से बाँध दिया जाए

    • यह तरीका उतना बड़ा फ़ायदा नहीं देता जितना लेख में कहा गया है। जैसे ही उपयोगकर्ता आता है, flow शुरू करके तुरंत असली provider पर redirect करने वाला phishing landing page बनाना काफ़ी आसान है
      Microsoft जैसे provider में, जहाँ उपयोगकर्ता को code खुद दर्ज करना पड़ता है, landing page निर्देश दिखाकर code को clipboard में copy भी कर सकता है, जिससे phishing का खतरा और बढ़ सकता है
  • अच्छा लेख है, और मैं इस बात से सहमत हूँ कि सबको RFC 8628 की ओर जाना चाहिए
    remote development machine पर CLI OAuth प्रक्रिया बहुत ज़्यादा बार झेलने के बाद, मैंने xdg-open को intercept करने और ports को अपने-आप forward करके खराब user experience को छिपाने वाला एक personal tool बनाया: https://github.com/phinze/bankshot

  • दिलचस्प। मैंने हाल ही में संयोग से “पुराना” authentication तरीका RFC 8252 implement किया था, लेकिन “नए” तरीके RFC 8268 के बारे में नहीं जानता था
    शायद ऐसा इसलिए क्योंकि मेरा मुख्य use case Google server authentication था। जिन documents को मैं RFC 8268 flow समझ रहा था, उनमें यह साफ़ लिखा है

    Alternatives

    If you are writing an app for a platform such as Android, iOS, macOS, Linux, or Windows (including the Universal Windows Platform), that has access to the browser and full input capabilities, use the OAuth 2.0 flow for mobile and desktop applications. (You should use that flow even if your app is a command-line tool without a graphical interface.)
    इसलिए मैंने बस RFC 8252 flow पढ़कर वही implement किया। मेरा tool CLI है, लेकिन उसका use case सिर्फ local था, इसलिए SSH या container environment को ध्यान में नहीं रखा
    ऊपर से, RFC 8268 flow में Google सिर्फ सीमित OAuth 2.0 scopes ही अनुमति देता है, इसलिए कुछ applications के लिए यह निर्णायक बाधा हो सकती है

    • छोटी-सी सुधार: मूल नंबर दोबारा देखे तो यह RFC 8628 है
      Google की scope restriction वही जगह है जहाँ OIDC की जटिलता उभरकर सामने आती है। आदर्श रूप से Google को access token में सब कुछ ठूँसने के बजाय ID token लौटाना चाहिए, लेकिन यह Google की OAuth configuration की समस्या है, 8628 की अपनी विशेषता नहीं
      OAuth की अंतहीन जटिलता यहीं से आती है। standard इस बात की रूपरेखा अच्छी तरह तय करता है कि authorization framework को कैसे बनाना और पहुँचाना है, लेकिन यह जानबूझकर चुप रहता है कि वह असल में क्या होना चाहिए। “ज़्यादातर” providers जिस common HTTP endpoints के सेट पर सहमत हैं, वहाँ तक पहुँचने के लिए भी OIDC के आविष्कार और कई साल लगे
  • एक और hack यह है कि server के xdg-open call को laptop तक forward किया जाए। मैंने personal infrastructure के लिए यह करने वाला एक छोटा tool बनाया है: https://github.com/zimbatm/subportal/

  • क्या दोनों approaches को जोड़ा नहीं जा सकता? localhost URL पर redirect करके hello वापस भेजा जाए, और अगर client को hello न मिले तो CLI में URL दिखा दिया जाए
    साथ ही, अगर server को भेजे गए hello का जवाब न मिले, तो browser में code दिखाकर “पुष्टि करें कि क्या आप login की कोशिश कर रहे हैं” जैसा संदेश दिखाया जा सकता है। Google की तरह फ़ोन पर चुनने के लिए नंबर दिखाकर इसे और आसान भी बनाया जा सकता है

    cli -> server/auth?r=localhost&fallback_choices=10,20,30  
    server -> localhost/hello
    
    Case 1: hello request received, go to redirect URI on localhost  
    Case 2: server has not received a hello reply, client has not received a hello request
    - CLI displays a/the webpage url and prompts for selecting a fallback_choice
    - Webpage displays a number say `20` from choices
      - Warn in the webpage not to share this code
    - User enters/selects it on the CLI
      - solves the token copy/paste problem if choices  
    

    फ़ायदा यह है कि case 2 में भी लोग लिंक पर click तो आसानी से कर लेते हैं, लेकिन OTP/code share अपेक्षाकृत कम करते हैं, और हमलावर को attack के दौरान लगातार social engineering में शामिल रहना पड़ता है

  • जब local machine पर यह ठीक से काम करता है, तब किसी interaction की ज़रूरत नहीं होती, इसलिए default browser-based flow होना चाहिए

    • यह flow भी जब सही चलता है तब browser-based ही काम करता है। बस failure की स्थिति में बेहतर fallback path देता है