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