MaxxRK / firstrade-api

A reverse engineered api to work with the Firstrade broker.
MIT License
30 stars 11 forks source link

Add MFA authentication #15

Open philiplin2345 opened 4 months ago

philiplin2345 commented 4 months ago

I'm using google authenticator and tried to add mfa to the existing codebase but failed in attempt. The code below is what I tried to insert into the login. Could you suggest what to do to correctly implement the mfa? Thanks!

if "/cgi-bin/sessionfailed?reason=6" in response.text:
            self.session.get(url=urls.login(), headers=headers)
            data = {
                "redirect": "",
                "ft_locale": "en-us",
                "login.x": "Log In",
                "username": r"" + self.username,
                "password": r"" + self.password,
                "destination_page": "home",
            }

            response = self.session.post(
                url=urls.login(),
                headers=headers,
                cookies=self.session.cookies,
                data=data,
            )
            print("login response: %s", response.text)
            mfa_code = 000222 ## replace this with the actual code
            data = {
                "destination_page": "home",
                "pin": mfa_code ,
            }

            self.session.post(
                url=urls.pin(), headers=headers, cookies=self.session.cookies, data=data
            )

            self.save_cookies()
             # Check if login was successful (a redirect is often indicated by a 302 status code)
            if response.status_code == 200:

                response = self.session.post("https://invest.firstrade.com/cgi-bin/enter_mfa", data)
                print("mfa response: %s", response.text)
                if response.ok:
                    print("Login and MFA successful!")
                else:
                    print("MFA failed!")
            else:
                print("Login failed!")

However print("mfa response: %s", response.text) gave me the response

mfa response: %s <style>.std{font-family:Verdana,Geneva,sans-serif;font-size:12px}.fineprint{font-family:Verdana,Geneva,sans-serif;font-size:10px;color:#999;text-align:center}.errrornum{font-family:Verdana,Geneva,sans-serif;font-size:25px;color:#036;font-weight:700;text-align:center}.homelink{font-family:Verdana,Geneva,sans-serif;font-size:12px;color:#036;font-weight:700}</style>
<title>Request Rejected</title>
<table align=center border=0 width=700><tr><td colspan=2 align=center><svg xmlns="http://www.w3.org/2000/svg" width="199" height="38.692" viewBox="0 0 199 38.692" aria-hidden="true" class="h-7 w-auto lg:h-10">
    <g id="ftlogo" transform="translate(-0.57 -0.5)">
        <path id="Path_414" data-name="Path 414" d="M44.76,5.45H57.018l-.98,5.512H51.017l-.935,5.225h4.465l-.935,5.247H49.147l-2.06,11.575H39.85Z" transform="translate(4.115 0.561)" fill="currentColor"/>
        <path id="Path_415" data-name="Path 415" d="M65.367,5.45l-4.91,27.559H53.22L58.13,5.45h7.237Z" transform="translate(5.528 0.561)" fill="currentColor"/>
        <path id="Path_416" data-name="Path 416" d="M68.03,5.45h5.121a37.789,37.789,0,0,1,6.869.4,3.808,3.808,0,0,1,2.605,2c.568,1.069.646,2.778.234,5.137A8.991,8.991,0,0,1,81.279,17.3a5.154,5.154,0,0,1-3.418,1.334A4.4,4.4,0,0,1,80.5,20.045a3.441,3.441,0,0,1,.635,1.62,25.2,25.2,0,0,1-.546,4.079L79.3,33.02H72.561l1.626-9.161a5.911,5.911,0,0,0,.134-2.745c-.167-.353-.757-.529-1.748-.529L70.357,33.009H63.12Zm6.4,4.718L73.341,16.3a3.581,3.581,0,0,0,1.77-.331q.551-.331.868-2.15l.267-1.51q.234-1.306-.167-1.72A2.271,2.271,0,0,0,74.432,10.168Z" transform="translate(6.544 0.561)" fill="currentColor"/>
        <path id="Path_417" data-name="Path 417" d="M99.627,13.852H92.9l.367-2.04a3.9,3.9,0,0,0,.067-1.82.782.782,0,0,0-.79-.4,1.338,1.338,0,0,0-1.08.529,3.539,3.539,0,0,0-.623,1.6,4.281,4.281,0,0,0,0,2.084,4.28,4.28,0,0,0,1.748,1.687q4.325,2.845,5.255,4.665c.612,1.213.69,3.176.212,5.878a11.511,11.511,0,0,1-1.47,4.345,7.029,7.029,0,0,1-3.106,2.349,11.912,11.912,0,0,1-4.81.948,9.3,9.3,0,0,1-4.765-1.092,4.159,4.159,0,0,1-2.193-2.779,13.753,13.753,0,0,1,.212-4.786l.323-1.8h6.725l-.59,3.353a3.978,3.978,0,0,0-.067,1.985c.134.3.445.441.924.441a1.465,1.465,0,0,0,1.18-.562,3.582,3.582,0,0,0,.646-1.665c.289-1.621.256-2.68-.1-3.187a16.438,16.438,0,0,0-2.939-2.5,25.875,25.875,0,0,1-3.117-2.57A4.711,4.711,0,0,1,83.851,16.3a9.069,9.069,0,0,1,.067-3.617,11.488,11.488,0,0,1,1.637-4.632A7.007,7.007,0,0,1,88.6,5.757a11.676,11.676,0,0,1,4.554-.827,10.376,10.376,0,0,1,4.643.9,3.911,3.911,0,0,1,2.227,2.272,11.356,11.356,0,0,1-.189,4.654Z" transform="translate(8.482 0.502)" fill="currentColor"/>
        <path id="Path_418" data-name="Path 418" d="M116.24,5.45l-.98,5.512h-4.3l-3.93,22.047H99.8l3.93-22.047H99.45l.98-5.512h15.81Z" transform="translate(10.36 0.561)" fill="currentColor"/>
        <path id="Path_419" data-name="Path 419" d="M117.3,5.45h5.121a37.789,37.789,0,0,1,6.869.4,3.808,3.808,0,0,1,2.605,2c.568,1.069.646,2.778.234,5.137a8.99,8.99,0,0,1-1.581,4.321,5.154,5.154,0,0,1-3.418,1.334,4.4,4.4,0,0,1,2.639,1.411,3.441,3.441,0,0,1,.635,1.62,25.2,25.2,0,0,1-.546,4.079l-1.292,7.276h-6.725l1.626-9.161a5.911,5.911,0,0,0,.134-2.745c-.178-.353-.757-.529-1.759-.529l-2.216,12.424H112.39Zm6.4,4.718L122.611,16.3a3.582,3.582,0,0,0,1.77-.331q.551-.331.868-2.15l.267-1.51q.234-1.306-.167-1.72A2.271,2.271,0,0,0,123.7,10.168Z" transform="translate(11.699 0.561)" fill="currentColor"/>
        <path id="Path_420" data-name="Path 420" d="M147.8,5.45l-.768,27.559H139.64l.49-4.961h-2.594l-1.314,4.961H128.74L137.346,5.45H147.8Zm-6.992,17.726q.284-4.679.957-11.575-2.522,7.92-3.451,11.575Z" transform="translate(13.415 0.561)" fill="currentColor"/>
        <path id="Path_421" data-name="Path 421" d="M151.979,5.45h5.411a33.274,33.274,0,0,1,7,.474,4.384,4.384,0,0,1,2.538,1.565,4.109,4.109,0,0,1,.768,2.425,38.181,38.181,0,0,1-.69,5.247l-1.715,9.657a24.26,24.26,0,0,1-1.236,4.961,4.91,4.91,0,0,1-1.581,1.962,6.176,6.176,0,0,1-2.338.981,20.443,20.443,0,0,1-3.93.287h-9.13Zm6.391,4.718L155.141,28.3a2.52,2.52,0,0,0,2.037-.617,10.1,10.1,0,0,0,.958-3.373l1.915-10.7a15.413,15.413,0,0,0,.312-2.4.955.955,0,0,0-.412-.783A3.176,3.176,0,0,0,158.37,10.168Z" transform="translate(15.193 0.561)" fill="currentColor"/>
        <path id="Path_422" data-name="Path 422" d="M170.24,5.45h12.069l-.98,5.512H176.5l-.935,5.225h4.52l-.935,5.247h-4.52l-1.08,6.063h5.311l-.98,5.512H165.33Z" transform="translate(17.261 0.561)" fill="currentColor"/>
        <g id="Group_175" data-name="Group 175" transform="translate(0.57 0.5)">
            <path id="Path_423" data-name="Path 423" d="M19.787,39.192V.5L.57,16.11l13.316-3.748Z" transform="translate(-0.57 -0.5)" fill="currentColor"/>
            <path id="Path_424" data-name="Path 424" d="M20.07,39.192V.5L39.287,16.11,25.971,12.362Z" transform="translate(1.641 -0.5)" fill="currentColor"/>
        </g>
    </g>
</svg>
<tr>
    <td colspan=2><hr size=1><tr><td colspan=2 align=center class=std><span class=errrornum>Request Rejected< span><tr><td colspan=2 align=center>
    <br>Support ID: 12594581709672916788<br>&nbsp;<tr>
                <td colspan=2 align=center class=std>The requested URL was rejected. However, if this is unexpected, please e-mail us with the support ID at service@firstrade.com or
                <a href="mailto:service@firstrade.com?subject=Rejected Request 12594581709672916788&body=Please review support ID 12594581709672916788 as it should not have happened.">click here</a> to open an email template, or please <a href=http://www.firstrade.com class=homelink>click here< a> to return to the home page.<tr><td width=50% height=100>
                <td width=50%>
                <tr>
                    <td colspan=2><div class=fineprint><p>Please review our
                    <a href=https://www.firstrade.com/content/en-us/aboutus/privacypolicy target=_blank>Privacy Policy< a> and
                    <a href=https://www.firstrade.com/content/en-us/customerservice/legalinfo target=_blank>Legal Disclaimer< a>.< p>©2018 Firstrade Securities Inc. All rights reserved. Member
                    <a href=https://www.finra.org target=_blank>FINRA</a>/<a href=https://www.sipc.org/ target=_blank>SIPC</a>.<br>System response and access times may vary due to market conditions, system performance, and other factors.< div>< table><p>
MaxxRK commented 4 months ago

I have not used totp in firstrade at all so I am not sure what the request looks like. I would have to snoop the network traffic and pull the code with something like this. https://pyauth.github.io/pyotp/ Do you still have to use a pin when you login with this method?

DrCrinkle commented 4 months ago

with pyotp you can use the QR code/string that is provided when you first set up 2fa

pyotp.TOTP(<2FA string>).now() will return the pin code that you can send to firstrade

MaxxRK commented 3 months ago

When I get some time, I will try to get this put in there.

MaxxRK commented 4 weeks ago

This is being worked on in the "mfa" branch.