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 <noreply@anthropic.com>
This commit is contained in:
Thigazhezhilan J 2026-05-26 21:49:28 +05:30
parent e447a39912
commit 9d1126b84d

View File

@ -187,20 +187,28 @@ def _perform_zerodha_login(
"Origin": "https://kite.zerodha.com", "Origin": "https://kite.zerodha.com",
}) })
# Step 1: Initialize OAuth session. # Step 1: Initialize OAuth session and capture sess_id.
# allow_redirects=False is CRITICAL: the first 302 response sets kf_session # sess_id is the OAuth session identifier that must be passed to twofa.
# with the OAuth context (api_key). Following the redirect updates kf_session # Without it, Zerodha cannot link the twofa request to the OAuth app and
# to a plain web session (no OAuth), which causes twofa to return profile:{} # returns profile:{} instead of redirect_url with request_token.
# instead of redirect_url with request_token. connect_resp = session.get(
session.get(
f"https://kite.zerodha.com/connect/login?v=3&api_key={api_key}", f"https://kite.zerodha.com/connect/login?v=3&api_key={api_key}",
timeout=15, timeout=15,
allow_redirects=False, 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( 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, 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 # Step 2: Username + password
login_resp = session.post( login_resp = session.post(
@ -223,20 +231,23 @@ def _perform_zerodha_login(
request_id = login_data["data"]["request_id"] 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: try:
import pyotp import pyotp
except ImportError: except ImportError:
raise AutoLoginError("pyotp is not installed on the server. Run: pip install pyotp==2.9.0") raise AutoLoginError("pyotp is not installed on the server. Run: pip install pyotp==2.9.0")
totp_value = pyotp.TOTP(totp_secret).now() totp_value = pyotp.TOTP(totp_secret).now()
twofa_resp = session.post( twofa_data = {
KITE_TWOFA_ENDPOINT,
data={
"user_id": zerodha_login_id, "user_id": zerodha_login_id,
"request_id": request_id, "request_id": request_id,
"twofa_value": totp_value, "twofa_value": totp_value,
"twofa_type": "totp", "twofa_type": "totp",
}, }
if sess_id:
twofa_data["sess_id"] = sess_id
twofa_resp = session.post(
KITE_TWOFA_ENDPOINT,
data=twofa_data,
timeout=15, timeout=15,
allow_redirects=False, allow_redirects=False,
) )