0
$\begingroup$

I am trying to replicate in Wolfram Language the functionality of the following Python code which uses Selenium:

    tradestation_headless_auth.py
import requests
import json
from urllib.parse import unquote
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

API_KEY = '*******' # Also called the `client_id`
SECRET_KEY = '*******'
REDIRECT_URI = 'http://localhost:8080' # Arbitrary for headless.
BASE_URL = 'https://sim-api.tradestation.com/v2'
USERNAME = "*******"
PASSWORD = "*******"

#
# Security questions and answers...
#
QUESTION_ONE = "*******"
QUESTION_TWO = "*******"
QUESTION_THREE = "*******"

ANSWER_ONE = "*******"
ANSWER_TWO = "*******"
ANSWER_THREE = "*******"

#
# Once we have the auth code, we can exchange it for the refresh token and access token.
#
def get_token_response(access_code):
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    post_data = {
            'grant_type': 'authorization_code',
            'client_id': API_KEY,
            'client_secret': SECRET_KEY,
            'redirect_uri': REDIRECT_URI,
            'code': access_code
        }
    r = requests.post(f'{BASE_URL}/Security/Authorize', headers=headers, data=post_data)
    try:
        return r.json()
    except:
        return sys.exc_info()[0]


#
# Start Selenium...
#
options = Options()
options.headless = True

driver = webdriver.Firefox(options=options)

auth_url = f"{BASE_URL}/authorize?redirect_uri={REDIRECT_URI}&client_id={API_KEY}&response_type=code"

try:
    driver.get(auth_url)

    elem = driver.find_element_by_name("username")
    elem.clear()
    elem.send_keys(USERNAME)

    elem = driver.find_element_by_name("password")
    elem.clear()
    elem.send_keys(PASSWORD)

    driver.find_element_by_id("btnLogin").click()

    elem = driver.find_element_by_name("ucQuestionAndAnswer$txtAnswer")
    elem.clear()

    if QUESTION_ONE in driver.page_source:
        elem.send_keys(ANSWER_ONE)
    elif QUESTION_TWO in driver.page_source:
        elem.send_keys(ANSWER_TWO)
    elif QUESTION_THREE in driver.page_source:
        elem.send_keys(ANSWER_THREE)
    else:
        print("Uh oh...") # Should probabaly raise exception here.

    driver.find_element_by_id("ucQuestionAndAnswer_btnLogin").click()

#
#  Lol. If you know a better way to do this, please let me know.
#
except Exception as e:
    s = unquote(e.msg) # `e.msg` is in UTF-8, using `unquote` just makes it easier to read/find the start of the access_code from the error message.  Not necessary, however.
    a, b = s.find("code="), s.find("&c=UTF-8")
    access_code = (s[a+5:b]) # The `+5` here is just the length of the string you used to `find` the start of the access_code.

token_response = get_token_response(access_code)
refresh_token = token_response['refresh_token']
access_token = token_response['access_token']

print("--- Token Response ---")
print(token_response)
print("--- Access Code ---")
print(access_code)
print("--- Access Token ---")
print(access_token)
print("--- Refresh Token ---")
print(refresh_token)

driver.close()

I started with the following:

authURL = 
  signInURL <> "/authorize?" <> "response_type=code" <> 
   "&client_id=" <> apiKey <> "&audience=" <> apiURL <> 
   "&redirect_uri=" <> redirectURI <> "&scope=" <> scope;
response = 
  URLRead[HTTPRequest[
    authURL, <|"Method" -> "POST", 
     "Headers" -> {"Content-Type" -> 
        "application/x-www-form-urlencoded"}, 
     "Body" -> "username=" <> username <> "&password=" <> password|>],
    "Body"];

authURL is correct, but response contains "Not Found", maybe because I an not using URLRead correctly.

Perhaps I need to take a completely different approach, possibly using StartWebSession[].

Any thoughts or guidance would be much appreciated.

$\endgroup$
1
  • $\begingroup$ (1) If the response is 404 Not found, then you probably have the wrong URL. (2) How are we supposed to help without any data? (3) There are plenty of examples in the documentation for URLRead. (4) The giant dump of python code does not really belong to this site, since this is a site about Mathematica ... $\endgroup$
    – Domen
    Mar 18 at 0:14

0

Browse other questions tagged or ask your own question.