module Network.OAuth.OAuth2.Internal where
import Control.Applicative ((<$>), (<*>))
import Control.Monad (mzero)
import Data.Aeson
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import Data.Maybe
import Data.Text.Encoding
import Network.HTTP.Types (renderSimpleQuery)
data OAuth2 = OAuth2 {
oauthClientId :: BS.ByteString
, oauthClientSecret :: BS.ByteString
, oauthOAuthorizeEndpoint :: BS.ByteString
, oauthAccessTokenEndpoint :: BS.ByteString
, oauthCallback :: Maybe BS.ByteString
} deriving (Show, Eq)
data AccessToken = AccessToken {
accessToken :: BS.ByteString
, refreshToken :: Maybe BS.ByteString
, expiresIn :: Maybe Int
, tokenType :: Maybe BS.ByteString
} deriving (Show)
instance FromJSON AccessToken where
parseJSON (Object o) = AccessToken <$> at <*> rt <*> ei <*> tt where
at = fmap encodeUtf8 $ o .: "access_token"
rt = fmap (fmap encodeUtf8) $ o .:? "refresh_token"
ei = o .:? "expires_in"
tt = fmap (fmap encodeUtf8) $ o .:? "token_type"
parseJSON _ = mzero
type OAuth2Result a = Either BSL.ByteString a
type QueryParams = [(BS.ByteString, BS.ByteString)]
type PostBody = [(BS.ByteString, BS.ByteString)]
type URI = BS.ByteString
authorizationUrl :: OAuth2 -> URI
authorizationUrl oa = oauthOAuthorizeEndpoint oa `appendQueryParam` queryStr
where queryStr = transform' [ ("client_id", Just $ oauthClientId oa)
, ("response_type", Just "code")
, ("redirect_uri", oauthCallback oa)]
accessTokenUrl :: OAuth2
-> BS.ByteString
-> (URI, PostBody)
accessTokenUrl oa code = accessTokenUrl' oa code (Just "authorization_code")
accessTokenUrl' :: OAuth2
-> BS.ByteString
-> Maybe BS.ByteString
-> (URI, PostBody)
accessTokenUrl' oa code gt = (uri, body)
where uri = oauthAccessTokenEndpoint oa
body = transform' [ ("client_id", Just $ oauthClientId oa)
, ("client_secret", Just $ oauthClientSecret oa)
, ("code", Just code)
, ("redirect_uri", oauthCallback oa)
, ("grant_type", gt) ]
refreshAccessTokenUrl :: OAuth2
-> BS.ByteString
-> (URI, PostBody)
refreshAccessTokenUrl oa rtoken = (uri, body)
where uri = oauthAccessTokenEndpoint oa
body = transform' [ ("client_id", Just $ oauthClientId oa)
, ("client_secret", Just $ oauthClientSecret oa)
, ("grant_type", Just "refresh_token")
, ("refresh_token", Just rtoken) ]
appendQueryParam :: URI -> QueryParams -> URI
appendQueryParam uri q = if "?" `BS.isInfixOf` uri
then uri `BS.append` "&" `BS.append` renderSimpleQuery False q
else uri `BS.append` renderSimpleQuery True q
appendAccessToken :: URI
-> AccessToken
-> URI
appendAccessToken uri t = appendQueryParam uri (accessTokenToParam t)
accessTokenToParam :: AccessToken -> QueryParams
accessTokenToParam (AccessToken token _ _ _) = [("access_token", token)]
transform' :: [(a, Maybe b)] -> [(a, b)]
transform' = map (\(a, Just b) -> (a, b)) . filter (isJust . snd)