Kotak-Neo / kotak-neo-api

113 stars 105 forks source link

[FEAT] Reuse Session Token to Initialize client without usename,password,OTP or MPIN #67

Open darshil-lakhani opened 1 year ago

darshil-lakhani commented 1 year ago

fixes #66

Step 1 : Initialize the client for the first time

from neo_api_client import NeoAPI
client = NeoAPI(consumer_key="", consumer_secret="", 
                environment='prod', on_message=on_message, on_error=on_error, on_close=None, on_open=None)
client.login(mobilenumber="+919999999999", password="XXXX")
client.session_2fa(OTP="")

Step 2 : Store the session info in "reuse_session" ( It is a JSON Dict obj ) ( You can store the json in a file or DB and then reuse it again anytime later )

import json

reuse_session = client.reuse_session

with open("creds.json","w") as file:
    file.write(json.dumps(reuse_session))

NOTE : reuse_session object contains these 4 things which are necessary for reusing the session again

{'access_token': '',
 'session_token': '',
 'sid': '',
 'serverId': ''}

Step 3 : Re-use the session multiple times in the following way, until token is expired

import json

with open("creds.json","w") as file:
    reuse_session = json.load(file)

client = NeoAPI(access_token="",environment="prod", reuse_session= reuse_session )

Now you can use the client object to access its methods.

prasadraju070 commented 1 year ago

please provide full working code for login and saving the session for reuse

geek-coder commented 1 year ago

Even with exiting code, you can pickle NeoAPI.configuration to a file. Then while initializing check pickle and create a NeoAPI object and assign this pickle configuraiton to newly created object. ... client = NeoAPI(consumer_key= cred['consumerKey'], consumer_secret=cred['consumerSecret'], environment='prod', on_message=cb_message, on_error=cb_error, on_close=cb_close, on_open= cb_open) client.configuration = clientconf print ("Returning a set session " ) return client

Now use client as you were using earlier NeoAPI after succussful 2fa auth .

Now if I see your given pull request, there is no code to save reuse session to a file. So reuse exactly when ? a) In the same run , for new request. b) Or in the next run,

If thas a) in the same run then whats use or reuse_session , you can anyways use orginal NeoAPI object. If thats b) i.e new run then anyways reuse_session will be null.

darshil-lakhani commented 1 year ago

@geek-coder I have mentioned that reuse_session variable is a dictionary object , you can easily store it in your database or in a file. I'm sure that much you can figure it out, my PR is giving a solution to extract a dictionary out of the client object which has all the necessary information to reuse the session.

There are multiple ways you can store them

  1. creds.json file
  2. SQL/Postgres/Mongo (use what ever you may like)
  3. creds.txt file

Answer to this > ( So reuse exactly when ? ) You can reuse it whenever you like, in the same run with same variable or in a next run by recalling it again from a file or DB.

I don't feel necessary to share the code of how you save a json object to a file or DB It is upon your choice.

I have edited the solution for your convenience

darshil-lakhani commented 1 year ago

please provide full working code for login and saving the session for reuse

Code given above is the full working code. reuse_session object is a json object which you can save to a file or DB and then reuse it in the next run

I have edited the solution for your convenience

ashxos commented 1 year ago

Thanks @darshil-lakhani !

It worked for me! Thanks for your efforts Darshil! I hope that the Kotak team merges this with the main code for everybody's benefit.

Aakashkr123 commented 12 months ago

Mandatory request headers for any action : {'Authorization': "Bearer " + self.bearer_token, "Sid": self.edit_sid, "Auth": self.edit_token, "neo-fin-key": self.neo_fin_key, "Content-Type": "application/x-www-form-urlencoded"}

Valid for the day and you need to genereate again next day. store this data with expire time so that if exipre <= datatime.datetime.now():

generate new credentails and store them

else:

assign this data to self.request_headers

and instead of using/writing full headers again and again, it's better to assing it to NeoUtility.request_headers() which increses speed n execution.

visit : https://github.com/Aakashkr123/kotak_neo/blob/main/login_api.py Line 138 - check for saved data return True/False Line 156 - Save data to json file. Line 108 - will generate session by fetching details.

It is for demo purpose and work in progress.

https://github.com/Aakashkr123/kotak_neo/blob/main/login_api.py

darshil-lakhani commented 11 months ago

@shashwat001 We are Good to merge this. This will help if user want's to store his session information for further purpose.

I guess we need to change the docs too, to let all know how to use it.

nishu88 commented 9 months ago

Does this stop spamming OTP's on phone? for every re-login?

darshil-lakhani commented 9 months ago

Does this stop spamming OTP's on phone? for every re-login?

Yes it does stop the OTP, once you start re using the session creds

hardikpatel043 commented 8 months ago

You can provide access_token instead of consumer_key and consumer_secret as below.

self.client = NeoAPI(consumer_key=self.consumer_key, consumer_secret=self.consumer_secret, environment=self.environment)

self.client = NeoAPI(access_token=currentToken, environment=self.environment)

rupanshugoyal commented 6 months ago

Any ETA on when this will be merged ?

jenbkite commented 6 months ago

Why do i get this error

Error: 'NeoAPI' object has no attribute 'reuse_session' Also this

I use this in the code

    # Initialize NeoAPI client
    client = NeoAPI(consumer_key=consumer_key, consumer_secret=consumer_secret, environment=environment)

    # Perform login and 2FA
    login_and_authenticate(client)

    # Convert reuse_session to JSON format
    reuse_session_json = json.dumps(client.reuse_session)
darshil-lakhani commented 6 months ago

You need to clone the PR first, then authenticate once using normal authentication method, then the reuse session is injected into the client object at the back end ( this is done in my PR, it is not in the main codebase)

After that you can reuse that by calling reuse session. I hope you are clear .

On Sat, Mar 30, 2024, 02:09 jenbkite @.***> wrote:

Why do i get this error

Error: 'NeoAPI' object has no attribute 'reuse_session' Also this

I use this in the code

# Initialize NeoAPI client
client = NeoAPI(consumer_key=consumer_key, consumer_secret=consumer_secret, environment=environment)

# Perform login and 2FA
login_and_authenticate(client)

# Convert reuse_session to JSON format
reuse_session_json = json.dumps(client.reuse_session)

— Reply to this email directly, view it on GitHub https://github.com/Kotak-Neo/kotak-neo-api/pull/67#issuecomment-2027715281, or unsubscribe https://github.com/notifications/unsubscribe-auth/ATZ4JJWIHTXJRONNMJAX47TY2XGQJAVCNFSM6AAAAAA5LE7UDKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRXG4YTKMRYGE . You are receiving this because you were mentioned.Message ID: @.***>

shusinghal commented 2 months ago

@darshil-lakhani Does this respect 2FA? I tried but it doesn't seem to work.

darshil-lakhani commented 2 months ago

@darshil-lakhani Does this respect 2FA? I tried but it doesn't seem to work.

Yes it respects 2FA. once the session is generated after the 2FA , it reuses the session itself after that, until the token is expired Please share your code and let me know where are you stuck exactly

shusinghal commented 2 months ago

@darshil-lakhani

  1. I copied the file from your PR to my code as for some reason I can't pull your request.
  2. Here is my code for your reference. I solved using pickle but sharing for the learning purpose.

def session(): client = NeoAPI(consumer_key=ckprod,consumer_secret=csprod,environment="PROD")

try:
    # Login using password
    client.login(mobilenumber="+91xxxxxxxxxx", password="yyyyyyyy")
    # Generate final Session Token
    client.session_2fa(OTP=xxxxxxx)

    reuse_session = client.reuse_session

    with open("creds.json","w") as file:
        file.write(json.dumps(reuse_session))
except Exception as e:
    print("Exception when calling SessionApi->session_2fa: %s\n" % e)

def bankNiftySession(): # in the below line, your code suggests to use 'w' method. However, it was giving error and 'r' method worked. with open("creds.json","r") as file: reuse_session = json.load(file)

client = NeoAPI(access_token="",environment="prod", reuse_session= reuse_session, consumer_key=ckprod, consumer_secret= csprod, neo_fin_key="neotradeapi" )
def on_message(message):
    print('[Res]: ', message)

def on_error(message):
    result = message
    print('[OnError]: ', result)
# Setup Callbacks for websocket events (Optional)
client.on_message = on_message  # called when message is received from websocket
client.on_error = on_error  # called when any error or exception occurs in code or websocket
client.on_close = None  # called when websocket connection is closed
client.on_open = None  # called when websocket successfully connects

inst_tokens = [{"instrument_token": "Nifty Bank", "exchange_segment": "nse_cm"},
            # {"instrument_token": "11536", "exchange_segment": "nse_cm"},
            # {"instrument_token": "1594", "exchange_segment": "nse_cm"},
            # {"instrument_token": "11915", "exchange_segment": "nse_cm"},
            # {"instrument_token": "13245", "exchange_segment": "nse_cm"}
            ]

try:
    # get LTP and Market Depth Data
    quo = client.quotes(instrument_tokens=inst_tokens, quote_type="", isIndex=True)
    print("quo: "+str(quo))
    high_price = float(quo['message'][0]['high_price'])
    low_price  = float(quo['message'][0]['low_price'])

    cePrice = float(math.ceil(high_price/100.0))*100
    pePrice = float(math.ceil(low_price/100.0))*100
    print("high is: "+str(cePrice)+" low is: "+str(pePrice))
# OR Quotes API can be accessed without completing login by passing session_token, sid, and server_id

    # client.search_scrip(exchange_segment = "nse_cm", symbol = "YESBANK",  expiry = "", option_type = "CE", strike_price = high_price)
    inst_tokens1 = [{"instrument_token": "NIFTY BANK", "exchange_segment": "nse_cm"}]

    # s = client.quotes(instrument_tokens= inst_tokens1, quote_type="", isIndex=True, session_token="", sid="",server_id="",on_error=on_error)
    # print("quotes: "+str(s))
    #client_subs = client.subscribe(instrument_tokens=inst_tokens1, isIndex=True, isDepth=True)
    client_sub = client.search_scrip(exchange_segment = "nse_cm", symbol = "YESBANK",  expiry = "", option_type = "", strike_price = "")
    print(str(client_sub))
    client_subs = client.search_scrip(exchange_segment="nse_fo", symbol="BANKNIFTY", expiry="30AUG2024", option_type="CE", strike_price="52700")
    print(str(client_subs))
except Exception as e:
    print("Exception when calling get Quote api->quotes: %s\n" % e)

session() bankNiftySession()

When I run the code, it says that 'exchange segment not available'. However, when I don't reuse session and run search_scrip after a fresh login, it works.

darshil-lakhani commented 2 months ago

@darshil-lakhani

When I run the code, it says that 'exchange segment not available'. However, when I don't reuse session and run search_scrip after a fresh login, it works.

Thanks for noticing this, this is because my PR is linked to the previous release of the lib. In that version search_scrip was not working. They have updated the lib after that, and I have not resolved those errors yet. That's the reason you are not able to use search_scrip with it.