Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rbh.authentication.login (username="....", password="....", mfa_code=totp) started failing on Dec 17 #521

Open
emmanuelsalawu opened this issue Dec 18, 2024 · 14 comments

Comments

@emmanuelsalawu
Copy link

Robinhood Authentication through MFA as described here https://robin-stocks.readthedocs.io/en/latest/quickstart.html#with-mfa-entered-programmatically-from-time-based-one-time-password-totp was working until Dec 17. I have tried multiple times but unsuccessful. Is anyone experiencing a similar issue?

The error message is not very helpful.

Traceback (most recent call last):
  File "rhs.py", line 962, in f2
    rbh_ = rbh.authentication.login (username="....", password="....", mfa_code=totp)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mycomputer/anaconda3/lib/python3.12/site-packages/robin_stocks/robinhood/authentication.py", line 198, in login
    raise Exception(data['detail'])
                    ~~~~^^^^^^^^^^
KeyError: 'detail'

I tried to print what data contains and obtained the following. (Note: data = request_post(url, payload) within the robin_stocks/robinhood/authentication.py).

{'verification_workflow': {'id': '***5d74a-****-****-9721-cb00a6d69***', 'workflow_status': 'workflow_status_internal_pending'}}

Could it be that the 'client_id': 'c82SH0WZOsabOXGP2sxqcj34FxkvfnWRZBKlBjFS', used in the payload used for authentication (within the robin_stocks/robinhood/authentication.py file) is no longer allowed by robinhood?

    url = login_url()
    payload = {
        'client_id': 'c82SH0WZOsabOXGP2sxqcj34FxkvfnWRZBKlBjFS',                                                                                                                                                             
        'expires_in': expiresIn,
        'grant_type': 'password',
        'password': password,
        'scope': scope,
        'username': username,
        'challenge_type': challenge_type,
        'device_token': device_token
    }

Any help will be greatly appreciated. Thank you.

@mitch-zink
Copy link

This was fixed recently, you need to pull the repo manually instead of using the package. The package was not updated

‘’’
echo "🍺 Adding or updating Robin-Stocks as a submodule..."
if [ -d "robin_stocks" ]; then
echo "🍺 Robin-Stocks submodule already exists. Pulling latest changes..."
git -C robin_stocks pull origin master
else
echo "🍺 Cloning Robin-Stocks as a submodule..."
git submodule add https://github.com/jmfernandes/robin_stocks.git robin_stocks
git submodule update --init --recursive
fi

echo "🍺 Installing Robin-Stocks in editable mode..."
pip install -e robin_stocks
‘’’

@SashaCroatia
Copy link

SashaCroatia commented Dec 19, 2024

This was fixed recently, you need to pull the repo manually instead of using the package. The package was not updated

Did just that. This is how I login:

#Login
load_dotenv()
rs.login(
    username=os.environ['robin_username'],
    password=os.environ['robin_password'],
    expiresIn=86400,
    by_sms=True,
    store_session=True
)

but now I get a different error:

Traceback (most recent call last):
  File "C:\Users\...", line #, in <module>
    rs.login(
  File "C:\Users\[user]\anaconda3\lib\site-packages\robin_stocks\robinhood\authentication.py", line 190, in login
    _validate_sherrif_id(device_token=device_token, workflow_id=workflow_id, mfa_code=mfa_code)
  File "C:\Users\[user]\anaconda3\lib\site-packages\robin_stocks\robinhood\authentication.py", line 230, in _validate_sherrif_id
    if challenge_response["status"] == "validated":
KeyError: 'status'

??

@mitch-zink
Copy link

I use TOTP, here's my code if you want to try:

import pyotp
import robin_stocks.robinhood as r
from prefect.blocks.system import Secret
from prefect.logging import get_run_logger

def load_prefect_credentials():
    """
    Loads credentials from Prefect Secret blocks.
    """
    logger = get_run_logger()
    try:
        username = Secret.load("robinhood-username").get()
        password = Secret.load("robinhood-password").get()
        mfa_key = Secret.load("robinhood-mfa-key").get()
    except Exception as e:
        logger.error("💩 Missing Robinhood credentials or MFA key in Prefect Secrets.")
        raise ValueError("💩 Missing Robinhood credentials or MFA key in Prefect Secrets") from e

    if not all([username, password, mfa_key]):
        logger.error("💩 Robinhood credentials or MFA key are missing. Check Prefect Secrets.")
        raise ValueError("💩 Robinhood credentials or MFA key are missing. Check Prefect Secrets.")

    return username, password, mfa_key


def generate_totp(mfa_key):
    """
    Generates a TOTP code using the provided MFA key.
    """
    logger = get_run_logger()
    totp = pyotp.TOTP(mfa_key).now()
    logger.info("🍺 Generated TOTP (MFA PIN)")
    return totp


def login_robinhood():
    """
    Logs into Robinhood using Prefect Secret credentials and a required MFA TOTP.
    """
    logger = get_run_logger()
    username, password, mfa_key = load_prefect_credentials()
    totp = generate_totp(mfa_key)

    try:
        logger.info("🍺 Attempting to log in to Robinhood...")
        login_response = r.login(
            username=username,
            password=password,
            store_session=False,
            mfa_code=totp
        )

        if isinstance(login_response, dict) and "access_token" in login_response:
            logger.info("🍺 Successfully logged into Robinhood")
        else:
            detail = login_response.get("detail", "No details provided.")
            logger.error(f"❌ Login failed: {detail}")
            raise ValueError(f"❌ Login failed: {detail}")
    except Exception as e:
        logger.error(f"❌ Exception during login: {e}")
        raise

@mitch-zink
Copy link

This is currently working fine for me

@emmanuelsalawu
Copy link
Author

Thank you so much, @mitch-zink! Your proposed solution works for me too, and I am using TOTP.
I will keep this open until after the market hours tomorrow to see if it continues to work.

@mitch-zink
Copy link

Thank you so much, @mitch-zink! Your proposed solution works for me too, and I am using TOTP. I will keep this open until after the market hours tomorrow to see if it continues to work.

You're welcome, glad it's working for you

@helhadry
Copy link

@mitch-zink from where we can get the mfa_key please ? its from the 2FA setting in robinhood website ?
image

@mitch-zink
Copy link

@mitch-zink from where we can get the mfa_key please ? its from the 2FA setting in robinhood website ? image

Click Two-Factor Authentication, Authenticator app, then follow the steps to use the MFA key you get to generate the TOTP/MFA pin like I did above

@helhadry
Copy link

@mitch-zink thank you will try this.

@emmanuelsalawu
Copy link
Author

Hello @helhadry ,

Try logging in using the MFA as described here https://robin-stocks.readthedocs.io/en/latest/quickstart.html#with-mfa-entered-programmatically-from-time-based-one-time-password-totp

import pyotp
import robin_stocks.robinhood as r
totp  = pyotp.TOTP("My2factorAppHere").now()
login = r.login('[email protected]','password', mfa_code=totp)

@helhadry
Copy link

@mitch-zink @emmanuelsalawu thank you for your help.

I tried to add the 2FA and selected the authentication app (Google authentication) but I can see only the backup code, where I can get the secret key (My2factorAppHere) ?

@emmanuelsalawu
Copy link
Author

emmanuelsalawu commented Dec 20, 2024 via email

@helhadry
Copy link

Yes I already did that but now I have only the 6 digits generated by Google authenticator app and If I put this code in the robin login it works fine, but I want to have something automatic to create that code without any human interaction.
the code that you suggest t to uses the "My2factorAppHere" and after that uses pyotp library to generate the otp code to use but I don't see where I can find that "My2factorAppHere".

thank you so much @emmanuelsalawu for your help on this.

@emmanuelsalawu
Copy link
Author

emmanuelsalawu commented Dec 20, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants
@helhadry @SashaCroatia @emmanuelsalawu @mitch-zink and others