From 9d1126b84d3d83f29f2e38b473c9adb04891f930 Mon Sep 17 00:00:00 2001 From: Thigazhezhilan J Date: Tue, 26 May 2026 21:49:28 +0530 Subject: [PATCH] Fix auto-login: pass sess_id to twofa to link request to OAuth app The sess_id from the connect/login redirect is Zerodha's OAuth session identifier. Without it in the twofa POST, Zerodha returns profile:{} (regular web login) instead of redirect_url with request_token. Co-Authored-By: Claude Sonnet 4.6 --- backend/app/services/auto_login_service.py | 39 ++++++++++++++-------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/backend/app/services/auto_login_service.py b/backend/app/services/auto_login_service.py index 16ed7aa..2313c2e 100644 --- a/backend/app/services/auto_login_service.py +++ b/backend/app/services/auto_login_service.py @@ -187,20 +187,28 @@ def _perform_zerodha_login( "Origin": "https://kite.zerodha.com", }) - # Step 1: Initialize OAuth session. - # allow_redirects=False is CRITICAL: the first 302 response sets kf_session - # with the OAuth context (api_key). Following the redirect updates kf_session - # to a plain web session (no OAuth), which causes twofa to return profile:{} - # instead of redirect_url with request_token. - session.get( + # Step 1: Initialize OAuth session and capture sess_id. + # sess_id is the OAuth session identifier that must be passed to twofa. + # Without it, Zerodha cannot link the twofa request to the OAuth app and + # returns profile:{} instead of redirect_url with request_token. + connect_resp = session.get( f"https://kite.zerodha.com/connect/login?v=3&api_key={api_key}", timeout=15, allow_redirects=False, ) + # Extract sess_id from the Location header redirect URL + connect_location = connect_resp.headers.get("Location", "") + sess_id = None + if "sess_id=" in connect_location: + sess_id = parse_qs(urlparse(connect_location).query).get("sess_id", [None])[0] print( - f"[AUTO-LOGIN-DEBUG] connect cookies={list(session.cookies.keys())}", + f"[AUTO-LOGIN-DEBUG] connect status={connect_resp.status_code} " + f"sess_id={sess_id} cookies={list(session.cookies.keys())}", flush=True, ) + # Follow the redirect so the server registers the sess_id against kf_session + if connect_location: + session.get(connect_location, timeout=15, allow_redirects=True) # Step 2: Username + password login_resp = session.post( @@ -223,20 +231,23 @@ def _perform_zerodha_login( request_id = login_data["data"]["request_id"] - # Step 3: TOTP + # Step 3: TOTP — include sess_id so Zerodha links this to the OAuth app try: import pyotp except ImportError: raise AutoLoginError("pyotp is not installed on the server. Run: pip install pyotp==2.9.0") totp_value = pyotp.TOTP(totp_secret).now() + twofa_data = { + "user_id": zerodha_login_id, + "request_id": request_id, + "twofa_value": totp_value, + "twofa_type": "totp", + } + if sess_id: + twofa_data["sess_id"] = sess_id twofa_resp = session.post( KITE_TWOFA_ENDPOINT, - data={ - "user_id": zerodha_login_id, - "request_id": request_id, - "twofa_value": totp_value, - "twofa_type": "totp", - }, + data=twofa_data, timeout=15, allow_redirects=False, )