Last active
March 18, 2019 18:15
-
-
Save chrischattin/f84616295d55fc6587a04e0762b994d6 to your computer and use it in GitHub Desktop.
Get an `access code` without running a webserver or interacting with a browser. Makes interacting with the Web API remotely more convenient.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment