jmfernandes / robin_stocks

This is a library to use with Robinhood Financial App. It currently supports trading crypto-currencies, options, and stocks. In addition, it can be used to get real time ticker information, assess the performance of your portfolio, and can also get tax documents, total dividends paid, and more. More info at
http://www.robin-stocks.com
MIT License
1.69k stars 459 forks source link

Authentication Timeout after 24hrs #47

Closed jmyers350 closed 4 years ago

jmyers350 commented 5 years ago

Was curious if someone had a workaround that would extend the Authentication almost indefinitely. I apologize if this is a redundant or previously solved issue, I haven't found a direct answer to this question yet.

class online_collect(): def login(self): username = 'xxxxxxx@hotmail.com' password = 'xxxxxxxxx' login = r.login(username,password, expiresIn = 3000000, by_sms = True, store_session = True)

Thanks

jmyers350 commented 5 years ago

Hello robin_stocks world.

So I have a workaround, although it doesn't solve the issue. It uses telegram as an option for correcting the prompt. If jmfernandes could shoot me a message I'd be happy to share my change with him so that everyone can use it! Thanks

jmyers350 commented 5 years ago

For those that want to use what I made, all it does is send a telegram prompt and allows you to remotely solve the challenge by responding to the Telegram message in telegram. To use this change, all you need to do is generate a telegram bot and retrieve the token from it. The changes I made are all in authentication.py and are as follows:

==========================================================================

import requests import json import time

def get_url(url): response = requests.get(url) content = response.content.decode("utf8") return content

def get_json_from_url(url): content = get_url(url) js = json.loads(content) return js

def get_updates(TOKEN): URL = "https://api.telegram.org/bot{}/".format(TOKEN) url = URL + "getUpdates" js = get_json_from_url(url) return js

def get_last_chat_id_and_text(updates): num_updates = len(updates["result"]) last_update = num_updates - 1 text = updates["result"][last_update]["message"]["text"] chat_id = updates["result"][last_update]["message"]["chat"]["id"] return (text, chat_id)

def custom(message, TOKEN): bot_message = message bot_token = TOKEN bot_chatID = '841481087' send_text = 'https://api.telegram.org/bot' + bot_token + '/sendMessage?chat_id=' + bot_chatID + '&parse_mode=Markdown&text=' + bot_message

response = requests.get(send_text)

return response.json()

===========================================================================

def login(username,password,expiresIn=86400,scope='internal',by_sms=True,store_session=True,telegram=False):

elif 'challenge' in data: challenge_id = data['challenge']['id']

    print('Robinhood Challenge Sent to User')
    if telegram == False:
        sms_code = input('Enter Robinhood code for validation: ')

    #==================================================================
    else:
        custom('What is the Robin Authentication?', telegram)
        draw = (get_last_chat_id_and_text(get_updates(telegram)))
        old_message = draw[0]

        while True:
            draw = (get_last_chat_id_and_text(get_updates(telegram)))
            new_message = draw[0]
            x = 0
            if old_message == new_message:
                x = x + 1
                if x == 60:
                    print('Failed to Receive Message')
                    break
                time.sleep(1)
            else:
                print('Message Received')
                print(new_message)
                break
        sms_code = new_message
    #================================================================

    res = respond_to_challenge(challenge_id, sms_code)
    while 'challenge' in res and res['challenge']['remaining_attempts'] > 0:
        sms_code = input('That code was not correct. {0} tries remaining. Please type in another code: '.format(res['challenge']['remaining_attempts']))
        res = respond_to_challenge(challenge_id, sms_code)
    helper.update_session('X-ROBINHOOD-CHALLENGE-RESPONSE-ID', challenge_id)
    data = helper.request_post(url,payload)
# Update Session data with authorization or raise exception with the information present in data.

BTW: I was not the original author of the telegram response code, I merely injected it as a test to see if this function would really work the way I wanted it to. The author and the location I got the telegram response code from can be found here: https://www.codementor.io/garethdwyer/building-a-telegram-bot-using-python-part-1-goi5fncay

jmfernandes commented 4 years ago

closing because the robinhood api is working as intended.

emberrett commented 2 years ago

There's actually a simple way to do this (from the docs):

With MFA entered programmatically from Time-based One-Time Password (TOTP) NOTE: to use this feature, you will have to sign into your robinhood account and turn on two factor authentication. Robinhood will ask you which two factor authorization app you want to use. Select “other”. Robinhood will present you with an alphanumeric code. This code is what you will use for “My2factorAppHere” in the code below. Run the following code and put the resulting MFA code into the prompt on your robinhood app.

import pyotp totp = pyotp.TOTP("My2factorAppHere").now() print("Current OTP:", totp)

Once you have entered the above MFA code (the totp variable that is printed out) into your Robinhood account, it will give you a backup code. Make sure you do not lose this code or you may be locked out of your account!!! You can also take the exact same “My2factorAppHere” from above and enter it into your phone’s authentication app, such as Google Authenticator. This will cause the exact same MFA code to be generated on your phone as well as your python code. This is important to do if you plan on being away from your computer and need to access your Robinhood account from your phone.

Now you should be able to login with the following code:

import pyotp import robin_stocks.robinhood as r totp = pyotp.TOTP("My2factorAppHere").now() login = r.login('joshsmith@email.com','password', mfa_code=totp)

Not all of the functions contained in the module need the user to be authenticated. A lot of the functions contained in the modules ‘stocks’ and ‘options’ do not require authentication, but it’s still good practice to log into Robinhood at the start of each script.