packages feed

hoauth2-0.3.0: example/Google/test.hs

{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}

{-

This is basically very manual test. Check following link for details.

Google web oauth: https://developers.google.com/accounts/docs/OAuth2WebServer

Google OAuth 2.0 playround: https://developers.google.com/oauthplayground/

-}

module Main where

import Network.OAuth.OAuth2.HttpClient
import Network.OAuth.OAuth2
import Keys (googleKey)

import Control.Applicative ((<$>), (<*>))
import Control.Monad (mzero)
import Data.Aeson (FromJSON, Value(Object), parseJSON, (.:), (.:?))
import Data.Aeson.TH (deriveJSON)
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Internal as BL
import Data.Text (Text)
import Prelude hiding (id)
import qualified Prelude as P (id)
import System.Environment (getArgs)

--------------------------------------------------

data Token = Token { issued_to   :: Text
                   , audience    :: Text
                   , user_id     :: Maybe Text
                   , scope       :: Text
                   , expires_in  :: Integer
                   , email       :: Maybe Text
                   , verified_email :: Maybe Bool
                   , access_type :: Text
                   } deriving (Show)

instance FromJSON Token where
    parseJSON (Object o) = Token
                           <$> o .:  "issued_to"
                           <*> o .:  "audience"
                           <*> o .:? "user_id"
                           <*> o .:  "scope"
                           <*> o .:  "expires_in"
                           <*> o .:? "email"
                           <*> o .:? "verified_email"
                           <*> o .:  "access_type"
    parseJSON _ = mzero

data User = User { id          :: Text
                 , name        :: Text
                 , given_name  :: Text
                 , family_name :: Text
                 , link        :: Text
                 , picture     :: Text
                 , gender      :: Text
                 , birthday    :: Text
                 , locale      :: Text
                 } deriving (Show)

$(deriveJSON P.id ''User)

--------------------------------------------------

main :: IO ()
main = do
    xs <- getArgs
    case xs of
        ["offline"] -> offlineCase
        _ -> normalCase

offlineCase :: IO ()
offlineCase = do
    print $ authorizationUrl googleKey `appendQueryParam'` googleScopeEmail `appendQueryParam'` googleAccessOffline
    putStrLn "visit the url and paste code here: "
    code <- fmap BS.pack getLine
    (Just (AccessToken accessToken refreshToken)) <- requestAccessToken googleKey code
    print (accessToken, refreshToken)
    validateToken accessToken >>= print
    (validateToken' accessToken :: IO (Maybe Token)) >>= print
    --
    -- obtain a new access token with refresh token, which turns out only in response at first time.
    -- Revoke Access https://www.google.com/settings/security
    --
    case refreshToken of
        Nothing -> print "Failed to fetch refresh token"
        Just tk -> do
            (Just (AccessToken accessToken refreshToken)) <- refreshAccessToken googleKey tk
            print (accessToken, refreshToken)
            validateToken accessToken >>= print
            (validateToken' accessToken :: IO (Maybe Token)) >>= print

normalCase :: IO ()
normalCase = do
    print $ authorizationUrl googleKey `appendQueryParam'` googleScopeUserInfo
    putStrLn "visit the url and paste code here: "
    code <- fmap BS.pack getLine
    (Just (AccessToken accessToken Nothing)) <- requestAccessToken googleKey code
    putStr "AccessToken: " >> print accessToken
    validateToken accessToken >>= print
    (validateToken' accessToken :: IO (Maybe Token)) >>= print
    userinfo accessToken >>= print
    (userinfo' accessToken :: IO (Maybe User)) >>= print

--------------------------------------------------
-- Google API

-- | This is special for google Gain read-only access to the user's email address.
googleScopeEmail :: QueryParams
googleScopeEmail = [("scope", "https://www.googleapis.com/auth/userinfo.email")]

-- | Gain read-only access to basic profile information, including a
googleScopeUserInfo :: QueryParams
googleScopeUserInfo = [("scope", "https://www.googleapis.com/auth/userinfo.profile")]

-- | Access offline
googleAccessOffline :: QueryParams
googleAccessOffline = [("access_type", "offline")
                      ,("approval_prompt", "force")]

-- | Token Validation
validateToken :: BS.ByteString -> IO BL.ByteString
validateToken accessToken = doSimpleGetRequest ("https://www.googleapis.com/oauth2/v1/tokeninfo" `appendQueryParam` (accessTokenToParam accessToken))

validateToken' :: FromJSON a => BS.ByteString -> IO (Maybe a)
validateToken' accessToken = doJSONGetRequest ("https://www.googleapis.com/oauth2/v1/tokeninfo" `appendQueryParam` (accessTokenToParam accessToken))

-- | fetch user email.
--   for more information, please check the playround site.
--
userinfo :: BS.ByteString -> IO BL.ByteString
userinfo accessToken = doSimpleGetRequest ("https://www.googleapis.com/oauth2/v2/userinfo" `appendQueryParam` (accessTokenToParam accessToken))

userinfo' :: FromJSON a => BS.ByteString -> IO (Maybe a)
userinfo' accessToken = doJSONGetRequest ("https://www.googleapis.com/oauth2/v2/userinfo" `appendQueryParam` (accessTokenToParam accessToken))