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

    -- | Bindings Authorization part of The OAuth 2.0 Authorization Framework
    -- RFC6749 <https://www.rfc-editor.org/rfc/rfc6749>
    module Network.OAuth.OAuth2.AuthorizationRequest where

    import Data.Aeson
    import Data.Function (on)
    import Data.List qualified as List
    import Data.Text.Encoding qualified as T
    import GHC.Generics (Generic)
    import Lens.Micro (over)
    import Network.OAuth.OAuth2.Internal
    import URI.ByteString

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

    -- * Errors

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

    instance FromJSON Errors where
      parseJSON :: Value -> Parser Errors
    parseJSON = Options -> Value -> Parser Errors
    forall a.
    (Generic a, GFromJSON Zero (Rep a)) =>
    Options -> Value -> Parser a
    genericParseJSON Options
    defaultOptions {constructorTagModifier :: String -> String
    constructorTagModifier = Char -> String -> String
    camelTo2 Char
    '_'}

    -- | Authorization Code Grant Error Responses https://tools.ietf.org/html/rfc6749#section-4.1.2.1
    -- I found hard time to figure a way to test the authorization error flow
    -- When anything wrong in @/authorize@ request, it will stuck at the Provider page
    -- hence no way for this library to parse error response.
    -- In other words, @/authorize@ ends up with 4xx or 5xx.
    -- Revisit this whenever find a case OAuth2 provider redirects back to Relying party with errors.
    data Errors
      = InvalidRequest
      | UnauthorizedClient
      | AccessDenied
      | UnsupportedResponseType
      | InvalidScope
      | ServerError
      | TemporarilyUnavailable
      deriving (Int -> Errors -> String -> String
    [Errors] -> String -> String
    Errors -> String
    (Int -> Errors -> String -> String)
    -> (Errors -> String)
    -> ([Errors] -> String -> String)
    -> Show Errors
    forall a.
    (Int -> a -> String -> String)
    -> (a -> String) -> ([a] -> String -> String) -> Show a
    $cshowsPrec :: Int -> Errors -> String -> String
    showsPrec :: Int -> Errors -> String -> String
    $cshow :: Errors -> String
    show :: Errors -> String
    $cshowList :: [Errors] -> String -> String
    showList :: [Errors] -> String -> String
    Show, Errors -> Errors -> Bool
    (Errors -> Errors -> Bool)
    -> (Errors -> Errors -> Bool) -> Eq Errors
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Errors -> Errors -> Bool
    == :: Errors -> Errors -> Bool
    $c/= :: Errors -> Errors -> Bool
    /= :: Errors -> Errors -> Bool
    Eq, (forall x. Errors -> Rep Errors x)
    -> (forall x. Rep Errors x -> Errors) -> Generic Errors
    forall x. Rep Errors x -> Errors
    forall x. Errors -> Rep Errors x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. Errors -> Rep Errors x
    from :: forall x. Errors -> Rep Errors x
    $cto :: forall x. Rep Errors x -> Errors
    to :: forall x. Rep Errors x -> Errors
    Generic)

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

    -- * URLs

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

    -- | See 'authorizationUrlWithParams'
    authorizationUrl :: OAuth2 -> URI
    authorizationUrl :: OAuth2 -> URI
    authorizationUrl = QueryParams -> OAuth2 -> URI
    authorizationUrlWithParams []

    -- | Prepare the authorization URL.  Redirect to this URL
    -- asking for user interactive authentication.
    --
    -- @since 2.6.0
    authorizationUrlWithParams :: QueryParams -> OAuth2 -> URI
    authorizationUrlWithParams :: QueryParams -> OAuth2 -> URI
    authorizationUrlWithParams QueryParams
    qs OAuth2
    oa = ASetter URI URI QueryParams QueryParams
    -> (QueryParams -> QueryParams) -> URI -> URI
    forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
    over ((Query -> Identity Query) -> URI -> Identity URI
    forall a (f :: * -> *).
    Functor f =>
    (Query -> f Query) -> URIRef a -> f (URIRef a)
    queryL ((Query -> Identity Query) -> URI -> Identity URI)
    -> ((QueryParams -> Identity QueryParams)
        -> Query -> Identity Query)
    -> ASetter URI URI QueryParams QueryParams
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (QueryParams -> Identity QueryParams) -> Query -> Identity Query
    Lens' Query QueryParams
    queryPairsL) (QueryParams -> QueryParams -> QueryParams
    forall a. [a] -> [a] -> [a]
    ++ QueryParams
    queryParts) (OAuth2 -> URI
    oauth2AuthorizeEndpoint OAuth2
    oa)
      where
        queryParts :: QueryParams
    queryParts =
          ((ByteString, ByteString) -> (ByteString, ByteString) -> Bool)
    -> QueryParams -> QueryParams
    forall a. (a -> a -> Bool) -> [a] -> [a]
    List.nubBy (ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    (==) (ByteString -> ByteString -> Bool)
    -> ((ByteString, ByteString) -> ByteString)
    -> (ByteString, ByteString)
    -> (ByteString, ByteString)
    -> Bool
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` (ByteString, ByteString) -> ByteString
    forall a b. (a, b) -> a
    fst) (QueryParams -> QueryParams) -> QueryParams -> QueryParams
    forall a b. (a -> b) -> a -> b
    $
            QueryParams
    qs
              QueryParams -> QueryParams -> QueryParams
    forall a. [a] -> [a] -> [a]
    ++ [ (ByteString
    "client_id", Text -> ByteString
    T.encodeUtf8 (Text -> ByteString) -> Text -> ByteString
    forall a b. (a -> b) -> a -> b
    $ OAuth2 -> Text
    oauth2ClientId OAuth2
    oa)
                 , (ByteString
    "response_type", ByteString
    "code")
                 , (ByteString
    "redirect_uri", URI -> ByteString
    forall a. URIRef a -> ByteString
    serializeURIRef' (URI -> ByteString) -> URI -> ByteString
    forall a b. (a -> b) -> a -> b
    $ OAuth2 -> URI
    oauth2RedirectUri OAuth2
    oa)
                 ]