packages feed

hoauth2-2.0.0: example/IDP/Okta.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}

module IDP.Okta where

import Data.Aeson
import Data.Bifunctor
import Data.Hashable
import Data.Text.Lazy (Text)
import GHC.Generics
import Keys
import Network.OAuth.OAuth2
import Types
import URI.ByteString
import URI.ByteString.QQ
import Utils

data Okta = Okta
  deriving (Show, Generic)

instance Hashable Okta

instance IDP Okta

instance HasLabel Okta

instance HasTokenReq Okta where
  tokenReq _ mgr = fetchAccessToken mgr oktaKey

instance HasTokenRefreshReq Okta where
  tokenRefreshReq _ mgr = refreshAccessToken mgr oktaKey

instance HasUserReq Okta where
  userReq _ mgr at = do
    re <- authGetJSON mgr at userInfoUri
    return (second toLoginUser re)

-- | https://developer.okta.com/docs/reference/api/oidc/#request-parameters
-- Okta Org AS doesn't support consent
-- Okta Custom AS does support consent via config (what scope shall prompt consent)
--
instance HasAuthUri Okta where
  authUri _ =
    createCodeUri
      oktaKey
      [ ("state", "Okta.test-state-123"),
        ( "scope",
          "openid profile"
          -- , "openid profile offline_access okta.users.read.self okta.users.read"
        ),
        ("prompt", "login consent")
      ]

data OktaUser = OktaUser
  { name :: Text,
    preferredUsername :: Text
  }
  deriving (Show, Generic)

instance FromJSON OktaUser where
  parseJSON =
    genericParseJSON defaultOptions {fieldLabelModifier = camelTo2 '_'}

userInfoUri :: URI
userInfoUri = [uri|https://hw2.trexcloud.com/oauth2/v1/userinfo|]

-- userInfoUri = [uri|https://dev-148986.oktapreview.com/oauth2/v1/userinfo|]

toLoginUser :: OktaUser -> LoginUser
toLoginUser ouser = LoginUser {loginUserName = name ouser}