module Servant.Auth.Server
  (
  -- | This package provides implementations for some common authentication
  -- methods. Authentication yields a trustworthy (because generated by the
  -- server) value of an some arbitrary type:
  --
  -- > type MyApi = Protected
  -- >
  -- > type Protected = Auth '[JWT, Cookie] User :> Get '[JSON] UserAccountDetails
  -- >
  -- > server :: Server Protected
  -- > server (Authenticated usr) = ... -- here we know the client really is
  -- >                                  -- who she claims to be
  -- > server _ = throwAll err401
  --
  -- Additional configuration happens via 'Context'.
  --
  -- == Example for Custom Handler
  -- To use a custom 'Servant.Server.Handler' it is necessary to use
  -- 'Servant.Server.hoistServerWithContext' instead of
  -- 'Servant.Server.hoistServer' and specify the 'Context'.
  --
  -- Below is an example of passing 'CookieSettings' and 'JWTSettings' in the
  -- 'Context' to create a specialized function equivalent to
  -- 'Servant.Server.hoistServer' for an API that includes cookie
  -- authentication.
  --
  -- > hoistServerWithAuth
  -- >   :: HasServer api '[CookieSettings, JWTSettings]
  -- >   => Proxy api
  -- >   -> (forall x. m x -> n x)
  -- >   -> ServerT api m
  -- >   -> ServerT api n
  -- > hoistServerWithAuth api =
  -- >   hoistServerWithContext api (Proxy :: Proxy '[CookieSettings, JWTSettings])

  ----------------------------------------------------------------------------
  -- * Auth
  -- | Basic types
    Auth
  , AuthResult(..)
  , AuthCheck(..)

  ----------------------------------------------------------------------------
  -- * JWT
  -- | JSON Web Tokens (JWT) are a compact and secure way of transferring
  -- information between parties. In this library, they are signed by the
  -- server (or by some other party posessing the relevant key), and used to
  -- indicate the bearer's identity or authorization.
  --
  -- Arbitrary information can be encoded - just declare instances for the
  -- 'FromJWT' and 'ToJWT' classes. Don't go overboard though - be aware that
  -- usually you'll be trasmitting this information on each request (and
  -- response!).
  --
  -- Note that, while the tokens are signed, they are not encrypted. Do not put
  -- any information you do not wish the client to know in them!

  -- ** Combinator
  -- | Re-exported from 'servant-auth'
  , JWT

  -- ** Classes
  , FromJWT(..)
  , ToJWT(..)

  -- ** Related types
  , IsMatch(..)

  -- ** Settings
  , JWTSettings(..)
  , defaultJWTSettings

  -- ** Create check
  , jwtAuthCheck


  ----------------------------------------------------------------------------
  -- * Cookie
  -- | Cookies are also a method of identifying and authenticating a user. They
  -- are particular common when the client is a browser

  -- ** Combinator
  -- | Re-exported from 'servant-auth'
  , Cookie

  -- ** Settings
  , CookieSettings(..)
  , XsrfCookieSettings(..)
  , defaultCookieSettings
  , defaultXsrfCookieSettings
  , makeSessionCookie
  , makeSessionCookieBS
  , makeXsrfCookie
  , makeCsrfCookie
  , makeCookie
  , makeCookieBS
  , acceptLogin
  , clearSession


  -- ** Related types
  , IsSecure(..)
  , SameSite(..)
  , AreAuths

  ----------------------------------------------------------------------------
  -- * BasicAuth
  -- ** Combinator
  -- | Re-exported from 'servant-auth'
  , BasicAuth

  -- ** Classes
  , FromBasicAuthData(..)

  -- ** Settings
  , BasicAuthCfg

  -- ** Related types
  , BasicAuthData(..)
  , IsPasswordCorrect(..)

  -- ** Authentication request
  , wwwAuthenticatedErr

  ----------------------------------------------------------------------------
  -- * Utilies
  , ThrowAll(throwAll)
  , generateKey
  , generateSecret
  , fromSecret
  , writeKey
  , readKey
  , makeJWT
  , verifyJWT

  -- ** Re-exports
  , Default(def)
  , SetCookie
  ) where

import Prelude hiding                           (readFile, writeFile)
import Data.ByteString                          (ByteString, writeFile, readFile)
import Data.Default.Class                       (Default (def))
import Servant.Auth
import Servant.Auth.JWT
import Servant.Auth.Server.Internal             ()
import Servant.Auth.Server.Internal.BasicAuth
import Servant.Auth.Server.Internal.Class
import Servant.Auth.Server.Internal.ConfigTypes
import Servant.Auth.Server.Internal.Cookie
import Servant.Auth.Server.Internal.JWT
import Servant.Auth.Server.Internal.ThrowAll
import Servant.Auth.Server.Internal.Types

import Crypto.JOSE as Jose
import Servant     (BasicAuthData (..))
import Web.Cookie  (SetCookie)

-- | Generate a key suitable for use with 'defaultConfig'.
generateKey :: IO Jose.JWK
generateKey :: IO JWK
generateKey = KeyMaterialGenParam -> IO JWK
forall (m :: * -> *). MonadRandom m => KeyMaterialGenParam -> m JWK
Jose.genJWK (KeyMaterialGenParam -> IO JWK) -> KeyMaterialGenParam -> IO JWK
forall a b. (a -> b) -> a -> b
$ Int -> KeyMaterialGenParam
Jose.OctGenParam Int
256

-- | Generate a bytestring suitable for use with 'fromSecret'.
generateSecret :: MonadRandom m => m ByteString
generateSecret :: m ByteString
generateSecret = Int -> m ByteString
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
Jose.getRandomBytes Int
256

-- | Restores a key from a bytestring.
fromSecret :: ByteString -> Jose.JWK
fromSecret :: ByteString -> JWK
fromSecret = ByteString -> JWK
forall s. Cons s s Word8 Word8 => s -> JWK
Jose.fromOctets

-- | Writes a secret to a file. Can for instance be used from the REPL
-- to persist a key to a file, which can then be included with the
-- application. Restore the key using 'readKey'.
writeKey :: FilePath -> IO ()
writeKey :: FilePath -> IO ()
writeKey FilePath
fp = FilePath -> ByteString -> IO ()
writeFile FilePath
fp (ByteString -> IO ()) -> IO ByteString -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO ByteString
forall (m :: * -> *). MonadRandom m => m ByteString
generateSecret

-- | Reads a key from a file.
readKey :: FilePath -> IO Jose.JWK
readKey :: FilePath -> IO JWK
readKey FilePath
fp = ByteString -> JWK
fromSecret (ByteString -> JWK) -> IO ByteString -> IO JWK
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> IO ByteString
readFile FilePath
fp