Search code examples
apioauthwindows-servicesetrade-api

ETrade API unattended authentication


Background
The ETrade authentication system has me creating a RequestToken, then executing an Authorization URL, which opens an ETrade page. The user logs in to authorize the activity on their account. They receive a pin, which they enter in my app. I call ExchangeRequestTokenForAccessToken with the RequestToken and the Pin. Then we are off and running.

Question
The problem is I'm creating a service that runs continuously in the background. There won't be any user to log in. Conversely, I won't be making any trades. Just crunching numbers, looking for stocks that meet certain criteria. I can't figure how to get this to work unattended.

Thanks, Brad.


Solution

  • Previously, I have used a series of WebRequests and manually added headers to simulate the authorization pages. This worked until about a year ago when ETrade complicated their headers with something that appears to be tracking information. I now use http://watin.org/ to log in, and to strip the Auth Code.

    Sloppy code looks like this:

                using WatiN.Core; // IE Automation
    ...
                // verify current thread in STA.
    
                Settings.Instance.MakeNewIeInstanceVisible = false;
    
                var ieStaticInstanceHelper = new IEStaticInstanceHelper();
                Settings.AutoStartDialogWatcher = false;
    
                using (ieStaticInstanceHelper.IE = new IE())
                {
                    string authCode = "";
                    ieStaticInstanceHelper.IE.GoTo(GetAuthorizationLink());
    
                    if (ieStaticInstanceHelper.IE.ContainsText("Scheduled System Maintenance"))
                    {
                        throw new ApplicationException("eTrade down for maintenance.");
                    }
    
                    TextField user = ieStaticInstanceHelper.IE.TextField(Find.ByName("USER"));
    
                    TextField pass = ieStaticInstanceHelper.IE.TextField(Find.ById("txtPassword"));
    
                    TextField pass2 = ieStaticInstanceHelper.IE.TextField(Find.ByName("PASSWORD"));
    
                    Button btn = ieStaticInstanceHelper.IE.Button(Find.ByClass("log-on-btn"));
                    Button btnAccept = ieStaticInstanceHelper.IE.Button(Find.ByValue("Accept"));
    
    
                    TextField authCodeBox = ieStaticInstanceHelper.IE.TextField(Find.First());
    
                    if (user != null && pass != null && btn != null &&
                        user.Exists && pass2.Exists && btn.Exists)
                    {
                        user.Value = username;
                        pass2.Value = password;
                        btn.Click();
                    }
    
                    btnAccept.WaitUntilExists(30);
                    btnAccept.Click();
    
                    authCodeBox.WaitUntilExists(30);
                    authCode = authCodeBox.Value;
    
                    SavePin(authCode);
                }