What's TOTP and How to generate It to Login into Zerodha Kite API using Python?

What's TOTP and How to generate It to Login into Zerodha Kite API using Python?
Yash Roongta

Published on Sep 18, 2021

6 min read

Subscribe to our newsletter and never miss any upcoming articles

Zerodha recently announced a significant change in its login flow via APIs where they made it mandatory to login via 2FA to place any orders via the KiteConnect APIs. This change is applicable from 3rd October 2021.

While this was optional between a PIN and a 2FA before, I am pretty sure 99% of the users used the PIN option just because it's hassle-free, and you can hard code it. But now, they have made it mandatory based on this SEBI Cyber Security Circular.

Naturally, the KiteConnect Forum did not take this very well. It is an inconvenience to non-coders who now have to go back to their developers and get their code changed to include TOTP verification or just move to another broker. If you are a non-coder and know at least a little bit of Python, this article will help you change your code to factor in TOTP verification instead of a PIN.

Quick Disclaimer: This article is only for educational purposes, and there is no intention to mislead readers to bypass the law via a quick hack. This is to show you how TOTP works. You can use it at your discretion.

What is TOTP?

TOTP (Time Based One Time Passwords) are unique numeric passwords that get generated with a standardized algorithm that uses the current time as an input. The time-based passwords are available offline and provide user-friendly, increased account security when used as a second factor. TOTP codes are generally only valid for 30 seconds.

TOTPs are generally more secure than SMS OTPs because SMS OTPs are static numbers that are only valid to be used once and are usually valid for more extended time periods like 5-10 mins. If someone clones your SIM CARD and gets access to the SMS OTP before you even enter it into the system, they can get into your account and do bad things.

Whereas TOTPs are generated on apps like Google Authenticator, and they are linked to specific Google Accounts, so it's a tad bit difficult to get into those and get access to TOTPs.

Why Zerodha is suddenly making it Mandatory?

Well, according to their forum, they have been questioned by the regulators several times on what steps they are taking to secure user funds, and accounts and TOTPs are the way forward. SEBI already recommended this in December 2018, but it is unclear why they waited until now to make it mandatory.

It is also quite baffling that no other broker has made it mandatory. Some other Broker APIs don't even require generating an accesstoken, their access is as simple as just providing the API KEY, USER ID, and USER PASSWORD.

All in all, I think each and everyone in the industry should welcome this move; after all, it is just more security to our accounts.

Introduction to PyOTP

So, how are we going to fix our TOTP problem in KiteConnect APIs? We will use this open-source library pyotp, long live Open Source Contributors.

You can install this library using pip install pyotp

Next, open up a Jupyter Notebook and try it out using the below code.

import pyotp

totp = pyotp.TOTP('ABCD')
totp.now()

image.png

What is happening under the hood is that we are giving the TOTP function in the pyotp module a secret key called ABCD and using the .now() function to generate the TOTP valid right now. If you try this 30 seconds later, the TOTP will automatically change; give it a try.

Zerodha 2FA registration will give you this secret key which you can provide to the function and use the .now() function to get the TOTP for that time. Confused? Move on to the next section.

Registering for 2FA TOTP on Zerodha

If you are already registered for 2FA, please unregister by going to the Password & Security Section on Kite and follow the below steps.

image.png

Once done, click again on Enable 2Factor TOTP, which will shoot out an OTP (How ironic?) on your registered email; verify that.

Now, before you move on to scanning the QR code generated, click on Can't scan? Copy the key. This is the key we give to the pyotp module.

This will generate a key like below. Please do not try and copy my key; I will have changed it by then :)

image.png

Now, go ahead and scan this QR code using the Google Authenticator App, and once then, let's try and put this key into the code we wrote above.

image.png

WIN_20210918_22_40_20_Pro (2).jpg

Yay! It Matches. Unfortunately, Google Authenticator doesn't allow you to take screenshots of its app, so I had to take pictures from another phone. So, we now have a solution; we just need to integrate it in our regular Selenium Workflow, which I guess everyone uses to get requestToken

Amending the Zerodha Login Script

Before all of this, please ensure you have all the required libraries to run the code; otherwise, it will not work correctly for you.

pip install undetected_chromedriver
pip install selenium
pip install kiteconnect

undetected_chromedriver is a selenium alternative where you don't have to worry about the Chromedriver version. You can use selenium as well if you prefer.

from kiteconnect import KiteConnect
from kiteconnect import KiteTicker
import undetected_chromedriver as uc
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
import time, pyotp

def login_in_zerodha(api_key, api_secret, user_id, user_pwd, totp_key):
    driver = uc.Chrome()
    driver.get(f'https://kite.trade/connect/login?api_key={api_key}&v=3')
    login_id = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_xpath('//*[@id="userid"]'))
    login_id.send_keys(user_id)

    pwd = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_xpath('//*[@id="password"]'))
    pwd.send_keys(user_pwd)

    submit = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_xpath('//*[@id="container"]/div/div/div[2]/form/div[4]/button'))
    submit.click()

    time.sleep(1)
    #adjustment to code to include totp
    totp = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_xpath('//*[@id="totp"]'))
    authkey = pyotp.TOTP(totp_key)
    totp.send_keys(authkey.now())
    #adjustment complete

    continue_btn = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_xpath('//*[@id="container"]/div/div/div[2]/form/div[3]/button'))
    continue_btn.click()

    time.sleep(5)

    url = driver.current_url
    initial_token = url.split('request_token=')[1]
    request_token = initial_token.split('&')[0]

    driver.close()

    kite = KiteConnect(api_key = api_key)
    #print(request_token)
    data = kite.generate_session(request_token, api_secret=api_secret)
    kite.set_access_token(data['access_token'])

    return kite

Please note, the assumption is that you already have a Zerodha login script that you want to amend; if you are unsure how I constructed the above code, you will be better off looking at my Youtube Channel with a detailed video soon.

Please check the above code where I have mentioned the adjustment starting line and ending. The function should accept the TOTP Key as a parameter we got from Zerodha, and it will return a KiteObj, which you can use to place orders, fetch holdings, and all the regular stuff.

You can use the below code to test if the function works or not.

kiteobj = login_in_zerodha('ZERODHA_API_KEY', 'ZERODHA_API_SECRET', 'ZERODHA_USER_ID', 'ZERODHA_USER_PWD', 'ZERODHA_TOTP_KEY')

print(kiteobj.profile())

Would you please Zoom In to see the below image properly to see the example?

image.png

Conclusion

That's pretty much it, guys! Change is hard, and Zerodha has always been the pioneer in bringing change and making the trading experience secure and user-friendly. TOTP is undoubtedly moving in that direction, it indeed temporarily causes a little bit of inconvenience, but it's worth it, and look how easy it is to fix it anyway!

I hope this article does help you. I have uploaded this code on Github here.

If you are still unsure how to fix your script, please fill in the Contact Us Form on the top with your details, and I will try and help you.

Feel free to reach out to me on Linkedin or Twitter. If you have any suggestions about the blog, you can use the Feedback widget on the right hand of your screen, and if you wish to Contact Us, you can fill in the form here.

If you like the content on Trade With Python, please do consider subscribing to our newsletter (you will find an option at the top of the page). Lastly, if you want to keep our spirits high and produce more content like this, you can BuyMeACoffee by clicking here or on the button below.

 
Share this

Impressum

Any information present on this blog does not constitute any form of investment advice or recommendation by Trade With Python.