{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Yesod.Auth.OAuth2.Nylas ( oauth2Nylas , module Yesod.Auth.OAuth2 ) where #if __GLASGOW_HASKELL__ < 710 import Control.Applicative ((<$>), (<*>)) #endif import Control.Monad (mzero) import Control.Exception.Lifted (throwIO) import Data.Aeson (FromJSON, Value(..), parseJSON, decode, (.:)) import Data.Monoid ((<>)) import Data.Text (Text) import Data.Text.Encoding (encodeUtf8, decodeUtf8) import Network.HTTP.Client (applyBasicAuth, httpLbs, parseRequest, responseBody, responseStatus) import Network.HTTP.Conduit (Manager) import Yesod.Auth (Creds(..), YesodAuth, AuthPlugin) import Yesod.Auth.OAuth2 (OAuth2(..), AccessToken(..), YesodOAuth2Exception(InvalidProfileResponse), authOAuth2) import qualified Network.HTTP.Types as HT data NylasAccount = NylasAccount { nylasAccountId :: Text , nylasAccountEmailAddress :: Text , nylasAccountName :: Text , nylasAccountProvider :: Text , nylasAccountOrganizationUnit :: Text } instance FromJSON NylasAccount where parseJSON (Object o) = NylasAccount <$> o .: "id" <*> o .: "email_address" <*> o .: "name" <*> o .: "provider" <*> o .: "organization_unit" parseJSON _ = mzero oauth2Nylas :: YesodAuth m => Text -- ^ Client ID -> Text -- ^ Client Secret -> AuthPlugin m oauth2Nylas clientId clientSecret = authOAuth2 "nylas" oauth fetchCreds where authorizeUrl = encodeUtf8 $ "https://api.nylas.com/oauth/authorize" <> "?response_type=code&scope=email&client_id=" <> clientId oauth = OAuth2 { oauthClientId = encodeUtf8 clientId , oauthClientSecret = encodeUtf8 clientSecret , oauthOAuthorizeEndpoint = authorizeUrl , oauthAccessTokenEndpoint = "https://api.nylas.com/oauth/token" , oauthCallback = Nothing } fetchCreds :: Manager -> AccessToken -> IO (Creds a) fetchCreds manager token = do req <- authorize <$> parseRequest "https://api.nylas.com/account" resp <- httpLbs req manager if HT.statusIsSuccessful (responseStatus resp) then case decode (responseBody resp) of Just ns -> return $ toCreds ns token Nothing -> throwIO parseFailure else throwIO requestFailure where authorize = applyBasicAuth (accessToken token) "" parseFailure = InvalidProfileResponse "nylas" "failed to parse account" requestFailure = InvalidProfileResponse "nylas" "failed to get account" toCreds :: NylasAccount -> AccessToken -> Creds a toCreds ns token = Creds { credsPlugin = "nylas" , credsIdent = nylasAccountId ns , credsExtra = [ ("email_address", nylasAccountEmailAddress ns) , ("name", nylasAccountName ns) , ("provider", nylasAccountProvider ns) , ("organization_unit", nylasAccountOrganizationUnit ns) , ("access_token", decodeUtf8 $ accessToken token) ] }