quickbooks-0.5.0.1: src/QuickBooks/Authentication.hs
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstraintKinds #-}
module QuickBooks.Authentication
( getTempOAuthCredentialsRequest
, getAccessTokensRequest
, oauthSignRequest
, authorizationURLForToken
, disconnectRequest
) where
import Control.Monad (void, liftM, ap)
import Data.Monoid ((<>))
import qualified Data.ByteString.Lazy as BSL
import Data.ByteString.Char8 (unpack, ByteString)
import Network.HTTP.Client (Manager
,Request(..)
,RequestBody(RequestBodyLBS)
,responseBody
,parseUrl
,httpLbs)
import Network.HTTP.Types.URI (parseSimpleQuery)
import Web.Authenticate.OAuth (signOAuth
,newCredential
,emptyCredential
,injectVerifier
,newOAuth
,OAuth(..))
import QuickBooks.Logging (logAPICall')
import QuickBooks.Types
getTempOAuthCredentialsRequest :: AppEnv
=> CallbackURL
-> IO (Either String (QuickBooksResponse OAuthToken)) -- ^ Temporary OAuthToken
getTempOAuthCredentialsRequest callbackURL =
return.handleQuickBooksTokenResponse "Couldn't get temporary tokens" =<< tokensRequest
where tokensRequest = getTokens temporaryTokenURL "?oauth_callback=" callbackURL oauthSignRequestWithEmptyCredentials
getAccessTokensRequest :: AppEnv
=> OAuthToken -- ^ Temporary Token
-> OAuthVerifier -- ^ OAuthVerifier provided by QuickBooks
-> IO (Either String (QuickBooksResponse OAuthToken)) -- ^ OAuthToken
getAccessTokensRequest tempToken verifier =
return.handleQuickBooksTokenResponse "Couldn't get access tokens" =<< tokensRequest
where
tokensRequest = getTokens accessTokenURL "?oauth_token=" (unpack $ token tempToken)
(oauthSignRequestWithVerifier verifier tempToken)
disconnectRequest :: AppEnv
=> OAuthToken
-> IO (Either String (QuickBooksResponse ()))
disconnectRequest tok = do
req <- parseUrl $ disconnectURL
req' <- oauthSignRequest tok req
void $ httpLbs req' ?manager
logAPICall' req'
return $ Right QuickBooksVoidResponse
getTokens :: AppEnv
=> String -- ^ Endpoint to request the token
-> String -- ^ URL parameter name
-> String -- ^ URL parameter value
-> ((?appConfig :: AppConfig) => Request -> IO Request) -- ^ Signing function
-> IO (Maybe OAuthToken)
getTokens tokenURL parameterName parameterValue signRequest = do
request <- parseUrl $ concat [tokenURL, parameterName, parameterValue]
request' <- signRequest request { method="POST", requestBody = RequestBodyLBS "" }
response <- httpLbs request' ?manager
logAPICall' request'
return $ tokensFromResponse (responseBody response)
oauthSignRequestWithVerifier :: (?appConfig :: AppConfig)
=> OAuthVerifier
-> OAuthToken
-> Request
-> IO Request
oauthSignRequestWithVerifier verifier tempTokens = signOAuth oauthApp credsWithVerifier
where
credentials = newCredential (token tempTokens)
(tokenSecret tempTokens)
credsWithVerifier = injectVerifier (unOAuthVerifier verifier) credentials
oauthApp = newOAuth { oauthConsumerKey = consumerToken ?appConfig
, oauthConsumerSecret = consumerSecret ?appConfig }
oauthSignRequest :: (?appConfig :: AppConfig)
=> OAuthToken
-> Request
-> IO Request
oauthSignRequest tok req = signOAuth oauthApp credentials req
where
credentials = newCredential (token tok)
(tokenSecret tok)
oauthApp = newOAuth { oauthConsumerKey = consumerToken ?appConfig
, oauthConsumerSecret = consumerSecret ?appConfig }
oauthSignRequestWithEmptyCredentials :: (?appConfig :: AppConfig)
=> Request
-> IO Request
oauthSignRequestWithEmptyCredentials = signOAuth oauthApp credentials
where
credentials = emptyCredential
oauthApp = newOAuth { oauthConsumerKey = consumerToken ?appConfig
, oauthConsumerSecret = consumerSecret ?appConfig }
disconnectURL :: String
disconnectURL = "https://appcenter.intuit.com/api/v1/connection/disconnect"
accessTokenURL :: String
accessTokenURL = "https://oauth.intuit.com/oauth/v1/get_access_token"
temporaryTokenURL :: String
temporaryTokenURL = "https://oauth.intuit.com/oauth/v1/get_request_token"
authorizationURL :: ByteString
authorizationURL = "https://appcenter.intuit.com/Connect/Begin"
authorizationURLForToken :: OAuthToken -> ByteString
authorizationURLForToken oatoken = authorizationURL <> "?oauth_token=" <> (token oatoken)
handleQuickBooksTokenResponse :: String -> Maybe OAuthToken -> Either String (QuickBooksResponse OAuthToken)
handleQuickBooksTokenResponse _ (Just tokensInResponse) = Right $ QuickBooksAuthResponse tokensInResponse
handleQuickBooksTokenResponse errorMessage Nothing = Left errorMessage
tokensFromResponse :: BSL.ByteString -> Maybe OAuthToken
tokensFromResponse response = OAuthToken `liftM` lookup "oauth_token" responseParams
`ap` lookup "oauth_token_secret" responseParams
where responseParams = parseSimpleQuery (BSL.toStrict response)