I have been long time fan of Haskell, but I had never engaged with a long term project to learn more about the language, the platform and all its possibilities, although I have a book pending to continue writing about Haskell FRP for Game development, this project seems like a good time/learn investment for long term goals: apply category theory, learn to trade stocks, explore Machine Learning algorithms and many more.
For all that, I started doing authentication to the platform, considering that I had to email ETrade customer service to request a Auth public/private key, then later with those in file, I created this script which will perform all necessary steps to retrieve a access token, which would allow me to query everything within the Sandbox: so here is the code:
{-# LANGUAGE OverloadedStrings #-}
module Network.Authenticate.ETradeOAuth
where
import Data.ByteString as BS
import Data.ByteString.Char8 as C8 (pack, unpack)
import Data.List as ML
import Data.Maybe
import Network.HTTP.Client
import Network.HTTP.Client.TLS
import Network.HTTP.Types.URI
import System.Environment
import System.IO ()
import Web.Authenticate.OAuth
import Web.Browser
authToken :: ByteString
authToken = "oauth_token"
-- OAuth Object to use when communicating with
-- ETrade developer API. Also, it must define
-- the two fields: oauthConsumerKey and oauthConsumerSecret
-- to be able to stablish a succesful communication.
-- For more information:
-- https://developer.etrade.com/ctnt/dev-portal/getArticleByCategory?category=Documentation
oa :: OAuth
oa = newOAuth {
oauthServerName = "ETrade"
, oauthRequestUri = "https://etws.etrade.com/oauth/request_token"
, oauthAccessTokenUri = "https://etws.etrade.com/oauth/access_token"
, oauthAuthorizeUri = "https://us.etrade.com/e/t/etws/authorize"
, oauthSignatureMethod = HMACSHA1
, oauthVersion = OAuth10a
, oauthConsumerKey = undefined
, oauthConsumerSecret = undefined
, oauthCallback = Just "oob"
}
-- We use a tlsManager to communicate using HTTPS
mgr :: IO Manager
mgr = newManager tlsManagerSettings
-- OAuth can construct automatically the authorization
-- URL, however ETrade uses another structure, which
-- is depicted as follows:
-- https://us.etrade.com/e/t/etws/authorize?key={oauth_consumer_key}&token={oauth_token}
etradeAuthUri :: OAuth -> Credential -> ByteString
etradeAuthUri oa crd = BS.concat [authUri, "?key=", consumerKey, "&token=", token]
where
authUri = C8.pack $ oauthAuthorizeUri oa
token = urlEncode True $ findAuth $ unCredential crd
consumerKey = urlEncode True $ oauthConsumerKey oa
-- Helper function to find the OAuth token out of a temporal credential
findAuth :: [(ByteString, ByteString)] -> ByteString
findAuth x = snd $ fromJust findAction
where
findFunction a = authToken == fst a
findAction = ML.find findFunction x
-- This will innitiate the OAuth process, using an OAuth object and
-- a TLS Manager to asking for a temporary credential, with which it
-- will redirect the user to a ETrade webpage in which access is
-- authorized and a confirmation string is provided
doInitialAuth :: OAuth -> Manager -> IO Credential
doInitialAuth oa m = do
temp <- --="" -="" ::="" able="" access="" all="" an="" are="" as="" authurl="" c8.unpack="" confirmation="" doaccessauth="" for="" gettemporarycredential="" in="" let="" m="" make="" oa="" oauth="" openbrowser="" place="" platform="" request="" return="" string="" subsequently="" temp="" the="" to="" token="" use="" we="" which="" will="" with=""> Manager -> ByteString -> Credential -> IO Credential
doAccessAuth oa m verifier tempCred = getAccessToken oa cred m
where cred = injectVerifier verifier tempCred
main :: IO Credential
main = do
print "This script will request an OAuth Token and Open the browser"
m <- a="" answer="" bs.getline="" bs.null="" code="" confirm="" confirmation="" continue="" cred="" do="" doaccessauth="" doinitialauth="" else="" if="" m="" mgr="" newcredential="" oa="" ot="" print="" requests:="" return="" rovide="" string="" temp="" the="" then="" to="" uth="" valid="">->->
Of course, the source could be found in Github with a GPL v3 license.
In general terms, we need to install and import the following libraries:
- bytestring
- authenticate-oauth
- http-client
- http-client-tls
- open-browser
With those already in place, it would be as simple as replace the values "oauthConsumerKey" and "oauthConsumerSecret" for those provided by ETrade or any other OAuth 1.0a service. Of course, if using other service, request URIs needs to be replaced.
After that, it is as simple as running this line:
runhaskell ETrade-OAuth-Example.hs.hs
That will automatically run main, which creates a TLS manager, request a token, opens the native OS browser to authorize the application and waits for the access code to finally request an access token from the API. All these steps were simplified using the OAuth library and the code snippet.
Of course, I am open to suggestion on how to improve this code is handled to make it more approachable to other interests.
Further Reading:
Github Source Code Link
Etrade Developer Documentation
OAuth Authentication process
No comments:
Post a Comment