diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2014, Zalora South East Asia Pte Ltd
+Copyright (c) 2014-2016, Zalora South East Asia Pte Ltd, Servant Contributors
 
 All rights reserved.
 
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,2 @@
-import Distribution.Simple
+import           Distribution.Simple
 main = defaultMain
diff --git a/include/overlapping-compat.h b/include/overlapping-compat.h
new file mode 100644
--- /dev/null
+++ b/include/overlapping-compat.h
@@ -0,0 +1,8 @@
+#if __GLASGOW_HASKELL__ >= 710
+#define OVERLAPPABLE_ {-# OVERLAPPABLE #-}
+#define OVERLAPPING_  {-# OVERLAPPING #-}
+#else
+{-# LANGUAGE OverlappingInstances #-}
+#define OVERLAPPABLE_
+#define OVERLAPPING_
+#endif
diff --git a/servant-client.cabal b/servant-client.cabal
--- a/servant-client.cabal
+++ b/servant-client.cabal
@@ -1,5 +1,5 @@
 name:                servant-client
-version:             0.4.4.7
+version:             0.5
 synopsis: automatical derivation of querying functions for servant webservices
 description:
   This library lets you derive automatically Haskell functions that
@@ -10,11 +10,12 @@
   <https://github.com/haskell-servant/servant/blob/master/servant-client/CHANGELOG.md CHANGELOG>
 license:             BSD3
 license-file:        LICENSE
-author:              Alp Mestanogullari, Sönke Hahn, Julian K. Arni
-maintainer:          alpmestan@gmail.com
-copyright:           2014 Zalora South East Asia Pte Ltd
+author:              Servant Contributors
+maintainer:          haskell-servant-maintainers@googlegroups.com
+copyright:           2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors
 category:            Web
 build-type:          Simple
+extra-source-files:  include/*.h
 cabal-version:       >=1.10
 tested-with:         GHC >= 7.8
 homepage:            http://haskell-servant.github.io/
@@ -26,28 +27,33 @@
 library
   exposed-modules:
     Servant.Client
+    Servant.Client.Experimental.Auth
     Servant.Common.BaseUrl
+    Servant.Common.BasicAuth
     Servant.Common.Req
   build-depends:
       base >=4.7 && <5
     , aeson
     , attoparsec
+    , base64-bytestring
     , bytestring
-    , either
     , exceptions
+    , http-api-data >= 0.1  && < 0.3
     , http-client
     , http-client-tls
     , http-media
     , http-types
     , network-uri >= 2.6
     , safe
-    , servant == 0.4.*
+    , servant == 0.5.*
     , string-conversions
     , text
     , transformers
+    , transformers-compat
   hs-source-dirs: src
   default-language: Haskell2010
   ghc-options: -Wall
+  include-dirs: include
 
 test-suite spec
   type: exitcode-stdio-1.0
@@ -61,10 +67,11 @@
     , Servant.Common.BaseUrlSpec
   build-depends:
       base == 4.*
+    , transformers
+    , transformers-compat
     , aeson
     , bytestring
     , deepseq
-    , either
     , hspec == 2.*
     , http-client
     , http-media
@@ -72,9 +79,9 @@
     , HUnit
     , network >= 2.6
     , QuickCheck >= 2.7
-    , servant == 0.4.*
+    , servant == 0.5.*
     , servant-client
-    , servant-server == 0.4.*
+    , servant-server == 0.5.*
     , text
     , wai
     , warp
diff --git a/src/Servant/Client.hs b/src/Servant/Client.hs
--- a/src/Servant/Client.hs
+++ b/src/Servant/Client.hs
@@ -4,19 +4,22 @@
 {-# LANGUAGE FlexibleInstances    #-}
 {-# LANGUAGE InstanceSigs         #-}
 {-# LANGUAGE OverloadedStrings    #-}
+{-# LANGUAGE PolyKinds            #-}
 {-# LANGUAGE ScopedTypeVariables  #-}
 {-# LANGUAGE TypeFamilies         #-}
 {-# LANGUAGE TypeOperators        #-}
 {-# LANGUAGE UndecidableInstances #-}
-#if !MIN_VERSION_base(4,8,0)
-{-# LANGUAGE OverlappingInstances #-}
-#endif
+
+#include "overlapping-compat.h"
 -- | This module provides 'client' which can automatically generate
 -- querying functions for each endpoint just from the type representing your
 -- API.
 module Servant.Client
-  ( client
+  ( AuthClientData
+  , AuthenticateReq(..)
+  , client
   , HasClient(..)
+  , mkAuthenticateReq
   , ServantError(..)
   , module Servant.Common.BaseUrl
   ) where
@@ -24,20 +27,21 @@
 #if !MIN_VERSION_base(4,8,0)
 import           Control.Applicative        ((<$>))
 #endif
-import           Control.Monad
-import           Control.Monad.Trans.Either
+import           Control.Monad.Trans.Except
 import           Data.ByteString.Lazy       (ByteString)
 import           Data.List
 import           Data.Proxy
 import           Data.String.Conversions
 import           Data.Text                  (unpack)
 import           GHC.TypeLits
-import           Network.HTTP.Client        (Response)
+import           Network.HTTP.Client        (Response, Manager)
 import           Network.HTTP.Media
 import qualified Network.HTTP.Types         as H
 import qualified Network.HTTP.Types.Header  as HTTP
 import           Servant.API
+import           Servant.Client.Experimental.Auth
 import           Servant.Common.BaseUrl
+import           Servant.Common.BasicAuth
 import           Servant.Common.Req
 
 -- * Accessing APIs as a Client
@@ -45,16 +49,16 @@
 -- | 'client' allows you to produce operations to query an API from a client.
 --
 -- > type MyApi = "books" :> Get '[JSON] [Book] -- GET /books
--- >         :<|> "books" :> ReqBody '[JSON] Book :> Post Book -- POST /books
+-- >         :<|> "books" :> ReqBody '[JSON] Book :> Post '[JSON] Book -- POST /books
 -- >
 -- > myApi :: Proxy MyApi
 -- > myApi = Proxy
 -- >
--- > getAllBooks :: EitherT String IO [Book]
--- > postNewBook :: Book -> EitherT String IO Book
--- > (getAllBooks :<|> postNewBook) = client myApi host
+-- > getAllBooks :: ExceptT String IO [Book]
+-- > postNewBook :: Book -> ExceptT String IO Book
+-- > (getAllBooks :<|> postNewBook) = client myApi host manager
 -- >   where host = BaseUrl Http "localhost" 8080
-client :: HasClient layout => Proxy layout -> BaseUrl -> Client layout
+client :: HasClient layout => Proxy layout -> BaseUrl -> Manager -> Client layout
 client p baseurl = clientWithRoute p defReq baseurl
 
 -- | This class lets us define how each API combinator
@@ -62,9 +66,8 @@
 -- an internal class, you can just use 'client'.
 class HasClient layout where
   type Client layout :: *
-  clientWithRoute :: Proxy layout -> Req -> BaseUrl -> Client layout
+  clientWithRoute :: Proxy layout -> Req -> BaseUrl -> Manager -> Client layout
 
-{-type Client layout = Client layout-}
 
 -- | A client querying function for @a ':<|>' b@ will actually hand you
 --   one function for querying @a@ and another one for querying @b@,
@@ -76,15 +79,15 @@
 -- > myApi :: Proxy MyApi
 -- > myApi = Proxy
 -- >
--- > getAllBooks :: EitherT String IO [Book]
--- > postNewBook :: Book -> EitherT String IO Book
--- > (getAllBooks :<|> postNewBook) = client myApi host
+-- > getAllBooks :: ExceptT String IO [Book]
+-- > postNewBook :: Book -> ExceptT String IO Book
+-- > (getAllBooks :<|> postNewBook) = client myApi host manager
 -- >   where host = BaseUrl Http "localhost" 8080
 instance (HasClient a, HasClient b) => HasClient (a :<|> b) where
   type Client (a :<|> b) = Client a :<|> Client b
-  clientWithRoute Proxy req baseurl =
-    clientWithRoute (Proxy :: Proxy a) req baseurl :<|>
-    clientWithRoute (Proxy :: Proxy b) req baseurl
+  clientWithRoute Proxy req baseurl manager =
+    clientWithRoute (Proxy :: Proxy a) req baseurl manager :<|>
+    clientWithRoute (Proxy :: Proxy b) req baseurl manager
 
 -- | If you use a 'Capture' in one of your endpoints in your API,
 -- the corresponding querying function will automatically take
@@ -93,7 +96,7 @@
 -- of this value at the right place in the request path.
 --
 -- You can control how values for this type are turned into
--- text by specifying a 'ToText' instance for your type.
+-- text by specifying a 'ToHttpApiData' instance for your type.
 --
 -- Example:
 --
@@ -102,103 +105,66 @@
 -- > myApi :: Proxy MyApi
 -- > myApi = Proxy
 -- >
--- > getBook :: Text -> EitherT String IO Book
--- > getBook = client myApi host
+-- > getBook :: Text -> ExceptT String IO Book
+-- > getBook = client myApi host manager
 -- >   where host = BaseUrl Http "localhost" 8080
 -- > -- then you can just use "getBook" to query that endpoint
-instance (KnownSymbol capture, ToText a, HasClient sublayout)
+instance (KnownSymbol capture, ToHttpApiData a, HasClient sublayout)
       => HasClient (Capture capture a :> sublayout) where
 
   type Client (Capture capture a :> sublayout) =
     a -> Client sublayout
 
-  clientWithRoute Proxy req baseurl val =
+  clientWithRoute Proxy req baseurl manager val =
     clientWithRoute (Proxy :: Proxy sublayout)
                     (appendToPath p req)
                     baseurl
+                    manager
 
-    where p = unpack (toText val)
+    where p = unpack (toUrlPiece val)
 
--- | If you have a 'Delete' endpoint in your API, the client
--- side querying function that is created when calling 'client'
--- will just require an argument that specifies the scheme, host
--- and port to send the request to.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPABLE #-}
-#endif
-  -- See https://downloads.haskell.org/~ghc/7.8.2/docs/html/users_guide/type-class-extensions.html#undecidable-instances
-  (MimeUnrender ct a, cts' ~ (ct ': cts)) => HasClient (Delete cts' a) where
-  type Client (Delete cts' a) = EitherT ServantError IO a
-  clientWithRoute Proxy req baseurl =
-    snd <$> performRequestCT (Proxy :: Proxy ct) H.methodDelete req [200, 202] baseurl
+instance OVERLAPPABLE_
+  -- Note [Non-Empty Content Types]
+  (MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts)
+  ) => HasClient (Verb method status cts' a) where
+  type Client (Verb method status cts' a) = ExceptT ServantError IO a
+  clientWithRoute Proxy req baseurl manager =
+    snd <$> performRequestCT (Proxy :: Proxy ct) method req baseurl manager
+      where method = reflectMethod (Proxy :: Proxy method)
 
--- | If you have a 'Delete xs ()' endpoint, the client expects a 204 No Content
--- HTTP header.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  HasClient (Delete cts ()) where
-  type Client (Delete cts ()) = EitherT ServantError IO ()
-  clientWithRoute Proxy req baseurl =
-    void $ performRequestNoBody H.methodDelete req [204] baseurl
+instance OVERLAPPING_
+  (ReflectMethod method) => HasClient (Verb method status cts NoContent) where
+  type Client (Verb method status cts NoContent) = ExceptT ServantError IO NoContent
+  clientWithRoute Proxy req baseurl manager =
+    performRequestNoBody method req baseurl manager >> return NoContent
+      where method = reflectMethod (Proxy :: Proxy method)
 
--- | If you have a 'Delete xs (Headers ls x)' endpoint, the client expects the
--- corresponding headers.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  -- See https://downloads.haskell.org/~ghc/7.8.2/docs/html/users_guide/type-class-extensions.html#undecidable-instances
-  ( MimeUnrender ct a, BuildHeadersTo ls, cts' ~ (ct ': cts)
-  ) => HasClient (Delete cts' (Headers ls a)) where
-  type Client (Delete cts' (Headers ls a)) = EitherT ServantError IO (Headers ls a)
-  clientWithRoute Proxy req baseurl = do
-    (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodDelete req [200, 202] baseurl
+instance OVERLAPPING_
+  -- Note [Non-Empty Content Types]
+  ( MimeUnrender ct a, BuildHeadersTo ls, ReflectMethod method, cts' ~ (ct ': cts)
+  ) => HasClient (Verb method status cts' (Headers ls a)) where
+  type Client (Verb method status cts' (Headers ls a))
+    = ExceptT ServantError IO (Headers ls a)
+  clientWithRoute Proxy req baseurl manager = do
+    let method = reflectMethod (Proxy :: Proxy method)
+    (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) method req baseurl manager
     return $ Headers { getResponse = resp
                      , getHeadersHList = buildHeadersTo hdrs
                      }
 
--- | If you have a 'Get' endpoint in your API, the client
--- side querying function that is created when calling 'client'
--- will just require an argument that specifies the scheme, host
--- and port to send the request to.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPABLE #-}
-#endif
-  (MimeUnrender ct result) => HasClient (Get (ct ': cts) result) where
-  type Client (Get (ct ': cts) result) = EitherT ServantError IO result
-  clientWithRoute Proxy req baseurl =
-    snd <$> performRequestCT (Proxy :: Proxy ct) H.methodGet req [200, 203] baseurl
-
--- | If you have a 'Get xs ()' endpoint, the client expects a 204 No Content
--- HTTP status.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  HasClient (Get (ct ': cts) ()) where
-  type Client (Get (ct ': cts) ()) = EitherT ServantError IO ()
-  clientWithRoute Proxy req baseurl =
-    performRequestNoBody H.methodGet req [204] baseurl
-
--- | If you have a 'Get xs (Headers ls x)' endpoint, the client expects the
--- corresponding headers.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  ( MimeUnrender ct a, BuildHeadersTo ls
-  ) => HasClient (Get (ct ': cts) (Headers ls a)) where
-  type Client (Get (ct ': cts) (Headers ls a)) = EitherT ServantError IO (Headers ls a)
-  clientWithRoute Proxy req baseurl = do
-    (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodGet req [200, 203, 204] baseurl
-    return $ Headers { getResponse = resp
+instance OVERLAPPING_
+  ( BuildHeadersTo ls, ReflectMethod method
+  ) => HasClient (Verb method status cts (Headers ls NoContent)) where
+  type Client (Verb method status cts (Headers ls NoContent))
+    = ExceptT ServantError IO (Headers ls NoContent)
+  clientWithRoute Proxy req baseurl manager = do
+    let method = reflectMethod (Proxy :: Proxy method)
+    hdrs <- performRequestNoBody method req baseurl manager
+    return $ Headers { getResponse = NoContent
                      , getHeadersHList = buildHeadersTo hdrs
                      }
 
+
 -- | If you use a 'Header' in one of your endpoints in your API,
 -- the corresponding querying function will automatically take
 -- an additional argument of the type specified by your 'Header',
@@ -207,12 +173,12 @@
 -- That function will take care of encoding this argument as Text
 -- in the request headers.
 --
--- All you need is for your type to have a 'ToText' instance.
+-- All you need is for your type to have a 'ToHttpApiData' instance.
 --
 -- Example:
 --
 -- > newtype Referer = Referer { referrer :: Text }
--- >   deriving (Eq, Show, Generic, FromText, ToText)
+-- >   deriving (Eq, Show, Generic, FromText, ToHttpApiData)
 -- >
 -- >            -- GET /view-my-referer
 -- > type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get '[JSON] Referer
@@ -220,143 +186,38 @@
 -- > myApi :: Proxy MyApi
 -- > myApi = Proxy
 -- >
--- > viewReferer :: Maybe Referer -> EitherT String IO Book
+-- > viewReferer :: Maybe Referer -> ExceptT String IO Book
 -- > viewReferer = client myApi host
 -- >   where host = BaseUrl Http "localhost" 8080
 -- > -- then you can just use "viewRefer" to query that endpoint
 -- > -- specifying Nothing or e.g Just "http://haskell.org/" as arguments
-instance (KnownSymbol sym, ToText a, HasClient sublayout)
+instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
       => HasClient (Header sym a :> sublayout) where
 
   type Client (Header sym a :> sublayout) =
     Maybe a -> Client sublayout
 
-  clientWithRoute Proxy req baseurl mval =
+  clientWithRoute Proxy req baseurl manager mval =
     clientWithRoute (Proxy :: Proxy sublayout)
                     (maybe req
                            (\value -> Servant.Common.Req.addHeader hname value req)
                            mval
                     )
                     baseurl
+                    manager
 
     where hname = symbolVal (Proxy :: Proxy sym)
 
--- | If you have a 'Post' endpoint in your API, the client
--- side querying function that is created when calling 'client'
--- will just require an argument that specifies the scheme, host
--- and port to send the request to.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPABLE #-}
-#endif
-  (MimeUnrender ct a) => HasClient (Post (ct ': cts) a) where
-  type Client (Post (ct ': cts) a) = EitherT ServantError IO a
-  clientWithRoute Proxy req baseurl =
-    snd <$> performRequestCT (Proxy :: Proxy ct) H.methodPost req [200, 201, 202] baseurl
-
--- | If you have a 'Post xs ()' endpoint, the client expects a 204 No Content
--- HTTP header.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  HasClient (Post (ct ': cts) ()) where
-  type Client (Post (ct ': cts) ()) = EitherT ServantError IO ()
-  clientWithRoute Proxy req baseurl =
-    void $ performRequestNoBody H.methodPost req [204] baseurl
-
--- | If you have a 'Post xs (Headers ls x)' endpoint, the client expects the
--- corresponding headers.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  ( MimeUnrender ct a, BuildHeadersTo ls
-  ) => HasClient (Post (ct ': cts) (Headers ls a)) where
-  type Client (Post (ct ': cts) (Headers ls a)) = EitherT ServantError IO (Headers ls a)
-  clientWithRoute Proxy req baseurl = do
-    (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodPost req [200, 201, 202] baseurl
-    return $ Headers { getResponse = resp
-                     , getHeadersHList = buildHeadersTo hdrs
-                     }
-
--- | If you have a 'Put' endpoint in your API, the client
--- side querying function that is created when calling 'client'
--- will just require an argument that specifies the scheme, host
--- and port to send the request to.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPABLE #-}
-#endif
-  (MimeUnrender ct a) => HasClient (Put (ct ': cts) a) where
-  type Client (Put (ct ': cts) a) = EitherT ServantError IO a
-  clientWithRoute Proxy req baseurl =
-    snd <$> performRequestCT (Proxy :: Proxy ct) H.methodPut req [200,201] baseurl
-
--- | If you have a 'Put xs ()' endpoint, the client expects a 204 No Content
--- HTTP header.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  HasClient (Put (ct ': cts) ()) where
-  type Client (Put (ct ': cts) ()) = EitherT ServantError IO ()
-  clientWithRoute Proxy req baseurl =
-    void $ performRequestNoBody H.methodPut req [204] baseurl
-
--- | If you have a 'Put xs (Headers ls x)' endpoint, the client expects the
--- corresponding headers.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  ( MimeUnrender ct a, BuildHeadersTo ls
-  ) => HasClient (Put (ct ': cts) (Headers ls a)) where
-  type Client (Put (ct ': cts) (Headers ls a)) = EitherT ServantError IO (Headers ls a)
-  clientWithRoute Proxy req baseurl = do
-    (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodPut req [200, 201] baseurl
-    return $ Headers { getResponse = resp
-                     , getHeadersHList = buildHeadersTo hdrs
-                     }
-
--- | If you have a 'Patch' endpoint in your API, the client
--- side querying function that is created when calling 'client'
--- will just require an argument that specifies the scheme, host
--- and port to send the request to.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPABLE #-}
-#endif
-  (MimeUnrender ct a) => HasClient (Patch (ct ': cts) a) where
-  type Client (Patch (ct ': cts) a) = EitherT ServantError IO a
-  clientWithRoute Proxy req baseurl =
-    snd <$> performRequestCT (Proxy :: Proxy ct) H.methodPatch req [200,201] baseurl
+-- | Using a 'HttpVersion' combinator in your API doesn't affect the client
+-- functions.
+instance HasClient sublayout
+  => HasClient (HttpVersion :> sublayout) where
 
--- | If you have a 'Patch xs ()' endpoint, the client expects a 204 No Content
--- HTTP header.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  HasClient (Patch (ct ': cts) ()) where
-  type Client (Patch (ct ': cts) ()) = EitherT ServantError IO ()
-  clientWithRoute Proxy req baseurl =
-    void $ performRequestNoBody H.methodPatch req [204] baseurl
+  type Client (HttpVersion :> sublayout) =
+    Client sublayout
 
--- | If you have a 'Patch xs (Headers ls x)' endpoint, the client expects the
--- corresponding headers.
-instance
-#if MIN_VERSION_base(4,8,0)
-         {-# OVERLAPPING #-}
-#endif
-  ( MimeUnrender ct a, BuildHeadersTo ls
-  ) => HasClient (Patch (ct ': cts) (Headers ls a)) where
-  type Client (Patch (ct ': cts) (Headers ls a)) = EitherT ServantError IO (Headers ls a)
-  clientWithRoute Proxy req baseurl = do
-    (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) H.methodPatch req [200, 201, 204] baseurl
-    return $ Headers { getResponse = resp
-                     , getHeadersHList = buildHeadersTo hdrs
-                     }
+  clientWithRoute Proxy =
+    clientWithRoute (Proxy :: Proxy sublayout)
 
 -- | If you use a 'QueryParam' in one of your endpoints in your API,
 -- the corresponding querying function will automatically take
@@ -369,7 +230,7 @@
 -- of inserting a textual representation of this value in the query string.
 --
 -- You can control how values for your type are turned into
--- text by specifying a 'ToText' instance for your type.
+-- text by specifying a 'ToHttpApiData' instance for your type.
 --
 -- Example:
 --
@@ -378,30 +239,31 @@
 -- > myApi :: Proxy MyApi
 -- > myApi = Proxy
 -- >
--- > getBooksBy :: Maybe Text -> EitherT String IO [Book]
+-- > getBooksBy :: Maybe Text -> ExceptT String IO [Book]
 -- > getBooksBy = client myApi host
 -- >   where host = BaseUrl Http "localhost" 8080
 -- > -- then you can just use "getBooksBy" to query that endpoint.
 -- > -- 'getBooksBy Nothing' for all books
 -- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
-instance (KnownSymbol sym, ToText a, HasClient sublayout)
+instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
       => HasClient (QueryParam sym a :> sublayout) where
 
   type Client (QueryParam sym a :> sublayout) =
     Maybe a -> Client sublayout
 
   -- if mparam = Nothing, we don't add it to the query string
-  clientWithRoute Proxy req baseurl mparam =
+  clientWithRoute Proxy req baseurl manager mparam =
     clientWithRoute (Proxy :: Proxy sublayout)
                     (maybe req
                            (flip (appendToQueryString pname) req . Just)
                            mparamText
                     )
                     baseurl
+                    manager
 
     where pname  = cs pname'
           pname' = symbolVal (Proxy :: Proxy sym)
-          mparamText = fmap toText mparam
+          mparamText = fmap toQueryParam mparam
 
 -- | If you use a 'QueryParams' in one of your endpoints in your API,
 -- the corresponding querying function will automatically take
@@ -415,7 +277,7 @@
 -- under the same query string parameter name.
 --
 -- You can control how values for your type are turned into
--- text by specifying a 'ToText' instance for your type.
+-- text by specifying a 'ToHttpApiData' instance for your type.
 --
 -- Example:
 --
@@ -424,30 +286,30 @@
 -- > myApi :: Proxy MyApi
 -- > myApi = Proxy
 -- >
--- > getBooksBy :: [Text] -> EitherT String IO [Book]
+-- > getBooksBy :: [Text] -> ExceptT String IO [Book]
 -- > getBooksBy = client myApi host
 -- >   where host = BaseUrl Http "localhost" 8080
 -- > -- then you can just use "getBooksBy" to query that endpoint.
 -- > -- 'getBooksBy []' for all books
 -- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
 -- > --   to get all books by Asimov and Heinlein
-instance (KnownSymbol sym, ToText a, HasClient sublayout)
+instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
       => HasClient (QueryParams sym a :> sublayout) where
 
   type Client (QueryParams sym a :> sublayout) =
     [a] -> Client sublayout
 
-  clientWithRoute Proxy req baseurl paramlist =
+  clientWithRoute Proxy req baseurl manager paramlist =
     clientWithRoute (Proxy :: Proxy sublayout)
                     (foldl' (\ req' -> maybe req' (flip (appendToQueryString pname) req' . Just))
                             req
                             paramlist'
                     )
-                    baseurl
+                    baseurl manager
 
     where pname  = cs pname'
           pname' = symbolVal (Proxy :: Proxy sym)
-          paramlist' = map (Just . toText) paramlist
+          paramlist' = map (Just . toQueryParam) paramlist
 
 -- | If you use a 'QueryFlag' in one of your endpoints in your API,
 -- the corresponding querying function will automatically take
@@ -465,7 +327,7 @@
 -- > myApi :: Proxy MyApi
 -- > myApi = Proxy
 -- >
--- > getBooks :: Bool -> EitherT String IO [Book]
+-- > getBooks :: Bool -> ExceptT String IO [Book]
 -- > getBooks = client myApi host
 -- >   where host = BaseUrl Http "localhost" 8080
 -- > -- then you can just use "getBooks" to query that endpoint.
@@ -477,152 +339,25 @@
   type Client (QueryFlag sym :> sublayout) =
     Bool -> Client sublayout
 
-  clientWithRoute Proxy req baseurl flag =
+  clientWithRoute Proxy req baseurl manager flag =
     clientWithRoute (Proxy :: Proxy sublayout)
                     (if flag
                        then appendToQueryString paramname Nothing req
                        else req
                     )
-                    baseurl
+                    baseurl manager
 
     where paramname = cs $ symbolVal (Proxy :: Proxy sym)
 
--- | If you use a 'MatrixParam' in one of your endpoints in your API,
--- the corresponding querying function will automatically take
--- an additional argument of the type specified by your 'MatrixParam',
--- enclosed in Maybe.
---
--- If you give Nothing, nothing will be added to the query string.
---
--- If you give a non-'Nothing' value, this function will take care
--- of inserting a textual representation of this value in the query string.
---
--- You can control how values for your type are turned into
--- text by specifying a 'ToText' instance for your type.
---
--- Example:
---
--- > type MyApi = "books" :> MatrixParam "author" Text :> Get '[JSON] [Book]
--- >
--- > myApi :: Proxy MyApi
--- > myApi = Proxy
--- >
--- > getBooksBy :: Maybe Text -> EitherT String IO [Book]
--- > getBooksBy = client myApi host
--- >   where host = BaseUrl Http "localhost" 8080
--- > -- then you can just use "getBooksBy" to query that endpoint.
--- > -- 'getBooksBy Nothing' for all books
--- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
-instance (KnownSymbol sym, ToText a, HasClient sublayout)
-      => HasClient (MatrixParam sym a :> sublayout) where
 
-  type Client (MatrixParam sym a :> sublayout) =
-    Maybe a -> Client sublayout
-
-  -- if mparam = Nothing, we don't add it to the query string
-  clientWithRoute Proxy req baseurl mparam =
-    clientWithRoute (Proxy :: Proxy sublayout)
-                    (maybe req
-                           (flip (appendToMatrixParams pname . Just) req)
-                           mparamText
-                    )
-                    baseurl
-
-    where pname = symbolVal (Proxy :: Proxy sym)
-          mparamText = fmap (cs . toText) mparam
-
--- | If you use a 'MatrixParams' in one of your endpoints in your API,
--- the corresponding querying function will automatically take an
--- additional argument, a list of values of the type specified by your
--- 'MatrixParams'.
---
--- If you give an empty list, nothing will be added to the query string.
---
--- Otherwise, this function will take care of inserting a textual
--- representation of your values in the path segment string, under the
--- same matrix string parameter name.
---
--- You can control how values for your type are turned into text by
--- specifying a 'ToText' instance for your type.
---
--- Example:
---
--- > type MyApi = "books" :> MatrixParams "authors" Text :> Get '[JSON] [Book]
--- >
--- > myApi :: Proxy MyApi
--- > myApi = Proxy
--- >
--- > getBooksBy :: [Text] -> EitherT String IO [Book]
--- > getBooksBy = client myApi host
--- >   where host = BaseUrl Http "localhost" 8080
--- > -- then you can just use "getBooksBy" to query that endpoint.
--- > -- 'getBooksBy []' for all books
--- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
--- > --   to get all books by Asimov and Heinlein
-instance (KnownSymbol sym, ToText a, HasClient sublayout)
-      => HasClient (MatrixParams sym a :> sublayout) where
-
-  type Client (MatrixParams sym a :> sublayout) =
-    [a] -> Client sublayout
-
-  clientWithRoute Proxy req baseurl paramlist =
-    clientWithRoute (Proxy :: Proxy sublayout)
-                    (foldl' (\ req' value -> maybe req' (flip (appendToMatrixParams pname) req' . Just . cs) value)
-                            req
-                            paramlist'
-                    )
-                    baseurl
-
-    where pname  = cs pname'
-          pname' = symbolVal (Proxy :: Proxy sym)
-          paramlist' = map (Just . toText) paramlist
-
--- | If you use a 'MatrixFlag' in one of your endpoints in your API,
--- the corresponding querying function will automatically take an
--- additional 'Bool' argument.
---
--- If you give 'False', nothing will be added to the path segment.
---
--- Otherwise, this function will insert a value-less matrix parameter
--- under the name associated to your 'MatrixFlag'.
---
--- Example:
---
--- > type MyApi = "books" :> MatrixFlag "published" :> Get '[JSON] [Book]
--- >
--- > myApi :: Proxy MyApi
--- > myApi = Proxy
--- >
--- > getBooks :: Bool -> EitherT String IO [Book]
--- > getBooks = client myApi host
--- >   where host = BaseUrl Http "localhost" 8080
--- > -- then you can just use "getBooks" to query that endpoint.
--- > -- 'getBooksBy False' for all books
--- > -- 'getBooksBy True' to only get _already published_ books
-instance (KnownSymbol sym, HasClient sublayout)
-      => HasClient (MatrixFlag sym :> sublayout) where
-
-  type Client (MatrixFlag sym :> sublayout) =
-    Bool -> Client sublayout
-
-  clientWithRoute Proxy req baseurl flag =
-    clientWithRoute (Proxy :: Proxy sublayout)
-                    (if flag
-                       then appendToMatrixParams paramname Nothing req
-                       else req
-                    )
-                    baseurl
-
-    where paramname = cs $ symbolVal (Proxy :: Proxy sym)
-
 -- | Pick a 'Method' and specify where the server you want to query is. You get
 -- back the full `Response`.
 instance HasClient Raw where
-  type Client Raw = H.Method -> EitherT ServantError IO (Int, ByteString, MediaType, [HTTP.Header], Response ByteString)
+  type Client Raw = H.Method -> ExceptT ServantError IO (Int, ByteString, MediaType, [HTTP.Header], Response ByteString)
 
-  clientWithRoute :: Proxy Raw -> Req -> BaseUrl -> Client Raw
-  clientWithRoute Proxy req baseurl httpMethod = do
-    performRequest httpMethod req (const True) baseurl
+  clientWithRoute :: Proxy Raw -> Req -> BaseUrl -> Manager -> Client Raw
+  clientWithRoute Proxy req baseurl manager httpMethod = do
+    performRequest httpMethod req baseurl manager
 
 -- | If you use a 'ReqBody' in one of your endpoints in your API,
 -- the corresponding querying function will automatically take
@@ -639,8 +374,8 @@
 -- > myApi :: Proxy MyApi
 -- > myApi = Proxy
 -- >
--- > addBook :: Book -> EitherT String IO Book
--- > addBook = client myApi host
+-- > addBook :: Book -> ExceptT String IO Book
+-- > addBook = client myApi host manager
 -- >   where host = BaseUrl Http "localhost" 8080
 -- > -- then you can just use "addBook" to query that endpoint
 instance (MimeRender ct a, HasClient sublayout)
@@ -649,23 +384,79 @@
   type Client (ReqBody (ct ': cts) a :> sublayout) =
     a -> Client sublayout
 
-  clientWithRoute Proxy req baseurl body =
+  clientWithRoute Proxy req baseurl manager body =
     clientWithRoute (Proxy :: Proxy sublayout)
                     (let ctProxy = Proxy :: Proxy ct
                      in setRQBody (mimeRender ctProxy body)
                                   (contentType ctProxy)
                                   req
                     )
-                    baseurl
+                    baseurl manager
 
 -- | Make the querying function append @path@ to the request path.
 instance (KnownSymbol path, HasClient sublayout) => HasClient (path :> sublayout) where
   type Client (path :> sublayout) = Client sublayout
 
-  clientWithRoute Proxy req baseurl =
+  clientWithRoute Proxy req baseurl manager =
      clientWithRoute (Proxy :: Proxy sublayout)
                      (appendToPath p req)
-                     baseurl
+                     baseurl manager
 
     where p = symbolVal (Proxy :: Proxy path)
 
+instance HasClient api => HasClient (Vault :> api) where
+  type Client (Vault :> api) = Client api
+
+  clientWithRoute Proxy req baseurl manager =
+    clientWithRoute (Proxy :: Proxy api) req baseurl manager
+
+instance HasClient api => HasClient (RemoteHost :> api) where
+  type Client (RemoteHost :> api) = Client api
+
+  clientWithRoute Proxy req baseurl manager =
+    clientWithRoute (Proxy :: Proxy api) req baseurl manager
+
+instance HasClient api => HasClient (IsSecure :> api) where
+  type Client (IsSecure :> api) = Client api
+
+  clientWithRoute Proxy req baseurl manager =
+    clientWithRoute (Proxy :: Proxy api) req baseurl manager
+
+instance HasClient subapi =>
+  HasClient (WithNamedContext name context subapi) where
+
+  type Client (WithNamedContext name context subapi) = Client subapi
+  clientWithRoute Proxy = clientWithRoute (Proxy :: Proxy subapi)
+
+instance ( HasClient api
+         ) => HasClient (AuthProtect tag :> api) where
+  type Client (AuthProtect tag :> api)
+    = AuthenticateReq (AuthProtect tag) -> Client api
+
+  clientWithRoute Proxy req baseurl manager (AuthenticateReq (val,func)) =
+    clientWithRoute (Proxy :: Proxy api) (func val req) baseurl manager
+
+-- * Basic Authentication
+
+instance HasClient api => HasClient (BasicAuth realm usr :> api) where
+  type Client (BasicAuth realm usr :> api) = BasicAuthData -> Client api
+
+  clientWithRoute Proxy req baseurl manager val =
+    clientWithRoute (Proxy :: Proxy api) (basicAuthReq val req) baseurl manager
+
+
+{- Note [Non-Empty Content Types]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Rather than have
+
+   instance (..., cts' ~ (ct ': cts)) => ... cts' ...
+
+It may seem to make more sense to have:
+
+   instance (...) => ... (ct ': cts) ...
+
+But this means that if another instance exists that does *not* require
+non-empty lists, but is otherwise more specific, no instance will be overall
+more specific. This in turn generally means adding yet another instance (one
+for empty and one for non-empty lists).
+-}
diff --git a/src/Servant/Client/Experimental/Auth.hs b/src/Servant/Client/Experimental/Auth.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/Client/Experimental/Auth.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE TypeFamilies      #-}
+
+-- | Authentication for clients
+
+module Servant.Client.Experimental.Auth (
+    AuthenticateReq(AuthenticateReq, unAuthReq)
+  , AuthClientData
+  , mkAuthenticateReq
+  ) where
+
+import Servant.Common.Req (Req)
+
+-- | For a resource protected by authentication (e.g. AuthProtect), we need
+-- to provide the client with some data used to add authentication data
+-- to a request
+--
+-- NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE
+type family AuthClientData a :: *
+
+-- | For better type inference and to avoid usage of a data family, we newtype
+-- wrap the combination of some 'AuthClientData' and a function to add authentication
+-- data to a request
+--
+-- NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE
+newtype AuthenticateReq a =
+  AuthenticateReq { unAuthReq :: (AuthClientData a, AuthClientData a -> Req -> Req) }
+
+-- | Handy helper to avoid wrapping datatypes in tuples everywhere.
+--
+-- NOTE: THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE
+mkAuthenticateReq :: AuthClientData a
+                  -> (AuthClientData a -> Req -> Req)
+                  -> AuthenticateReq a
+mkAuthenticateReq val func = AuthenticateReq (val, func)
diff --git a/src/Servant/Common/BaseUrl.hs b/src/Servant/Common/BaseUrl.hs
--- a/src/Servant/Common/BaseUrl.hs
+++ b/src/Servant/Common/BaseUrl.hs
@@ -1,12 +1,23 @@
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE ViewPatterns #-}
-module Servant.Common.BaseUrl where
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric      #-}
+{-# LANGUAGE ViewPatterns       #-}
+module Servant.Common.BaseUrl (
+  -- * types
+    BaseUrl (..)
+  , InvalidBaseUrlException
+  , Scheme (..)
+  -- * functions
+  , parseBaseUrl
+  , showBaseUrl
+) where
 
-import Data.List
-import GHC.Generics
-import Network.URI
-import Safe
-import Text.Read
+import           Control.Monad.Catch (Exception, MonadThrow, throwM)
+import           Data.List
+import           Data.Typeable
+import           GHC.Generics
+import           Network.URI hiding (path)
+import           Safe
+import           Text.Read
 
 -- | URI scheme to use
 data Scheme =
@@ -18,14 +29,22 @@
 --   for servant's automatically-generated clients.
 data BaseUrl = BaseUrl
   { baseUrlScheme :: Scheme -- ^ URI scheme to use
-  , baseUrlHost :: String   -- ^ host (eg "haskell.org")
-  , baseUrlPort :: Int      -- ^ port (eg 80)
-  } deriving (Show, Eq, Ord, Generic)
+  , baseUrlHost   :: String   -- ^ host (eg "haskell.org")
+  , baseUrlPort   :: Int      -- ^ port (eg 80)
+  , baseUrlPath   :: String   -- ^ path (eg "/a/b/c")
+  } deriving (Show, Ord, Generic)
 
+instance Eq BaseUrl where
+    BaseUrl a b c path == BaseUrl a' b' c' path'
+        = a == a' && b == b' && c == c' && s path == s path'
+        where s ('/':x) = x
+              s x       = x
+
 showBaseUrl :: BaseUrl -> String
-showBaseUrl (BaseUrl urlscheme host port) =
-  schemeString ++ "//" ++ host ++ portString
+showBaseUrl (BaseUrl urlscheme host port path) =
+  schemeString ++ "//" ++ host ++ (portString </> path)
     where
+      a </> b = if "/" `isPrefixOf` b || null b then a ++ b else a ++ '/':b
       schemeString = case urlscheme of
         Http  -> "http:"
         Https -> "https:"
@@ -34,20 +53,23 @@
         (Https, 443) -> ""
         _ -> ":" ++ show port
 
-parseBaseUrl :: String -> Either String BaseUrl
+data InvalidBaseUrlException = InvalidBaseUrlException String deriving (Show, Typeable)
+instance Exception InvalidBaseUrlException
+
+parseBaseUrl :: MonadThrow m => String -> m BaseUrl
 parseBaseUrl s = case parseURI (removeTrailingSlash s) of
   -- This is a rather hacky implementation and should be replaced with something
   -- implemented in attoparsec (which is already a dependency anyhow (via aeson)).
-  Just (URI "http:" (Just (URIAuth "" host (':' : (readMaybe -> Just port)))) "" "" "") ->
-    Right (BaseUrl Http host port)
-  Just (URI "http:" (Just (URIAuth "" host "")) "" "" "") ->
-    Right (BaseUrl Http host 80)
-  Just (URI "https:" (Just (URIAuth "" host (':' : (readMaybe -> Just port)))) "" "" "") ->
-    Right (BaseUrl Https host port)
-  Just (URI "https:" (Just (URIAuth "" host "")) "" "" "") ->
-    Right (BaseUrl Https host 443)
+  Just (URI "http:" (Just (URIAuth "" host (':' : (readMaybe -> Just port)))) path "" "") ->
+    return (BaseUrl Http host port path)
+  Just (URI "http:" (Just (URIAuth "" host "")) path "" "") ->
+    return (BaseUrl Http host 80 path)
+  Just (URI "https:" (Just (URIAuth "" host (':' : (readMaybe -> Just port)))) path "" "") ->
+    return (BaseUrl Https host port path)
+  Just (URI "https:" (Just (URIAuth "" host "")) path "" "") ->
+    return (BaseUrl Https host 443 path)
   _ -> if "://" `isInfixOf` s
-    then Left ("invalid base url: " ++ s)
+    then throwM (InvalidBaseUrlException $ "Invalid base URL: " ++ s)
     else parseBaseUrl ("http://" ++ s)
  where
   removeTrailingSlash str = case lastMay str of
diff --git a/src/Servant/Common/BasicAuth.hs b/src/Servant/Common/BasicAuth.hs
new file mode 100644
--- /dev/null
+++ b/src/Servant/Common/BasicAuth.hs
@@ -0,0 +1,21 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE TypeFamilies      #-}
+
+-- | Basic Authentication for clients
+
+module Servant.Common.BasicAuth (
+    basicAuthReq
+  ) where
+
+import Data.ByteString.Base64 (encode)
+import Data.Monoid ((<>))
+import Data.Text.Encoding (decodeUtf8)
+import Servant.Common.Req (addHeader, Req)
+import Servant.API.BasicAuth (BasicAuthData(BasicAuthData))
+
+-- | Authenticate a request using Basic Authentication
+basicAuthReq :: BasicAuthData -> Req -> Req
+basicAuthReq (BasicAuthData user pass) req =
+    let authText = decodeUtf8 ("Basic " <> encode (user <> ":" <> pass))
+    in addHeader "Authorization" authText req
diff --git a/src/Servant/Common/Req.hs b/src/Servant/Common/Req.hs
--- a/src/Servant/Common/Req.hs
+++ b/src/Servant/Common/Req.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE DeriveDataTypeable  #-}
 {-# LANGUAGE CPP                 #-}
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE ScopedTypeVariables #-}
@@ -10,27 +11,26 @@
 import Control.Monad
 import Control.Monad.Catch (MonadThrow)
 import Control.Monad.IO.Class
-import Control.Monad.Trans.Either
+import Control.Monad.Trans.Except
 import Data.ByteString.Lazy hiding (pack, filter, map, null, elem)
-import Data.IORef
 import Data.String
 import Data.String.Conversions
 import Data.Proxy
 import Data.Text (Text)
 import Data.Text.Encoding
-import Network.HTTP.Client hiding (Proxy)
-import Network.HTTP.Client.TLS
+import Data.Typeable
+import Network.HTTP.Client hiding (Proxy, path)
 import Network.HTTP.Media
 import Network.HTTP.Types
 import qualified Network.HTTP.Types.Header   as HTTP
-import Network.URI
+import Network.URI hiding (path)
 import Servant.API.ContentTypes
 import Servant.Common.BaseUrl
-import Servant.Common.Text
-import System.IO.Unsafe
 
 import qualified Network.HTTP.Client as Client
 
+import Web.HttpApiData
+
 data ServantError
   = FailureResponse
     { responseStatus            :: Status
@@ -46,15 +46,17 @@
     { responseContentType       :: MediaType
     , responseBody              :: ByteString
     }
-  | ConnectionError
-    { connectionError           :: HttpException
-    }
   | InvalidContentTypeHeader
     { responseContentTypeHeader :: ByteString
     , responseBody              :: ByteString
     }
-  deriving (Show)
+  | ConnectionError
+    { connectionError           :: SomeException
+    }
+  deriving (Show, Typeable)
 
+instance Exception ServantError
+
 data Req = Req
   { reqPath   :: String
   , qs        :: QueryText
@@ -70,13 +72,6 @@
 appendToPath p req =
   req { reqPath = reqPath req ++ "/" ++ p }
 
-appendToMatrixParams :: String
-                     -> Maybe String
-                     -> Req
-                     -> Req
-appendToMatrixParams pname pvalue req =
-  req { reqPath = reqPath req ++ ";" ++ pname ++ maybe "" ("=" ++) pvalue }
-
 appendToQueryString :: Text       -- ^ param name
                     -> Maybe Text -- ^ param value
                     -> Req
@@ -85,17 +80,17 @@
   req { qs = qs req ++ [(pname, pvalue)]
       }
 
-addHeader :: ToText a => String -> a -> Req -> Req
+addHeader :: ToHttpApiData a => String -> a -> Req -> Req
 addHeader name val req = req { headers = headers req
-                                      ++ [(name, toText val)]
+                                      ++ [(name, decodeUtf8 (toHeader val))]
                              }
 
 setRQBody :: ByteString -> MediaType -> Req -> Req
 setRQBody b t req = req { reqBody = Just (b, t) }
 
 reqToRequest :: (Functor m, MonadThrow m) => Req -> BaseUrl -> m Request
-reqToRequest req (BaseUrl reqScheme reqHost reqPort) =
-    fmap (setheaders . setAccept . setrqb . setQS ) $ parseUrl url
+reqToRequest req (BaseUrl reqScheme reqHost reqPort path) =
+    setheaders . setAccept . setrqb . setQS <$> parseUrl url
 
   where url = show $ nullURI { uriScheme = case reqScheme of
                                   Http  -> "http:"
@@ -105,7 +100,7 @@
                                          , uriRegName = reqHost
                                          , uriPort = ":" ++ show reqPort
                                          }
-                             , uriPath = reqPath req
+                             , uriPath = path ++ reqPath req
                              }
 
         setrqb r = case reqBody req of
@@ -125,66 +120,59 @@
 
 -- * performing requests
 
-{-# NOINLINE __manager #-}
-__manager :: IORef Manager
-__manager = unsafePerformIO (newManager tlsManagerSettings >>= newIORef)
-
-__withGlobalManager :: (Manager -> IO a) -> IO a
-__withGlobalManager action = readIORef __manager >>= action
-
-
 displayHttpRequest :: Method -> String
 displayHttpRequest httpmethod = "HTTP " ++ cs httpmethod ++ " request"
 
 
-performRequest :: Method -> Req -> (Int -> Bool) -> BaseUrl
-               -> EitherT ServantError IO ( Int, ByteString, MediaType
+performRequest :: Method -> Req -> BaseUrl -> Manager
+               -> ExceptT ServantError IO ( Int, ByteString, MediaType
                                           , [HTTP.Header], Response ByteString)
-performRequest reqMethod req isWantedStatus reqHost = do
+performRequest reqMethod req reqHost manager = do
   partialRequest <- liftIO $ reqToRequest req reqHost
 
   let request = partialRequest { Client.method = reqMethod
                                , checkStatus = \ _status _headers _cookies -> Nothing
                                }
 
-  eResponse <- liftIO $ __withGlobalManager $ \ manager ->
-    catchHttpException $
-    Client.httpLbs request manager
+  eResponse <- liftIO $ catchConnectionError $ Client.httpLbs request manager
   case eResponse of
     Left err ->
-      left $ ConnectionError err
+      throwE . ConnectionError $ SomeException err
 
     Right response -> do
       let status = Client.responseStatus response
           body = Client.responseBody response
-          hrds = Client.responseHeaders response
+          hdrs = Client.responseHeaders response
           status_code = statusCode status
       ct <- case lookup "Content-Type" $ Client.responseHeaders response of
                  Nothing -> pure $ "application"//"octet-stream"
                  Just t -> case parseAccept t of
-                   Nothing -> left $ InvalidContentTypeHeader (cs t) body
+                   Nothing -> throwE $ InvalidContentTypeHeader (cs t) body
                    Just t' -> pure t'
-      unless (isWantedStatus status_code) $
-        left $ FailureResponse status ct body
-      return (status_code, body, ct, hrds, response)
+      unless (status_code >= 200 && status_code < 300) $
+        throwE $ FailureResponse status ct body
+      return (status_code, body, ct, hdrs, response)
 
 
 performRequestCT :: MimeUnrender ct result =>
-  Proxy ct -> Method -> Req -> [Int] -> BaseUrl -> EitherT ServantError IO ([HTTP.Header], result)
-performRequestCT ct reqMethod req wantedStatus reqHost = do
+  Proxy ct -> Method -> Req -> BaseUrl -> Manager
+    -> ExceptT ServantError IO ([HTTP.Header], result)
+performRequestCT ct reqMethod req reqHost manager = do
   let acceptCT = contentType ct
-  (_status, respBody, respCT, hrds, _response) <-
-    performRequest reqMethod (req { reqAccept = [acceptCT] }) (`elem` wantedStatus) reqHost
-  unless (matches respCT (acceptCT)) $ left $ UnsupportedContentType respCT respBody
+  (_status, respBody, respCT, hdrs, _response) <-
+    performRequest reqMethod (req { reqAccept = [acceptCT] }) reqHost manager
+  unless (matches respCT (acceptCT)) $ throwE $ UnsupportedContentType respCT respBody
   case mimeUnrender ct respBody of
-    Left err -> left $ DecodeFailure err respCT respBody
-    Right val -> return (hrds, val)
+    Left err -> throwE $ DecodeFailure err respCT respBody
+    Right val -> return (hdrs, val)
 
-performRequestNoBody :: Method -> Req -> [Int] -> BaseUrl -> EitherT ServantError IO ()
-performRequestNoBody reqMethod req wantedStatus reqHost = do
-  _ <- performRequest reqMethod req (`elem` wantedStatus) reqHost
-  return ()
+performRequestNoBody :: Method -> Req -> BaseUrl -> Manager
+  -> ExceptT ServantError IO [HTTP.Header]
+performRequestNoBody reqMethod req reqHost manager = do
+  (_status, _body, _ct, hdrs, _response) <- performRequest reqMethod req reqHost manager
+  return hdrs
 
-catchHttpException :: IO a -> IO (Either HttpException a)
-catchHttpException action =
-  catch (Right <$> action) (pure . Left)
+catchConnectionError :: IO a -> IO (Either ServantError a)
+catchConnectionError action =
+  catch (Right <$> action) $ \e ->
+    pure . Left . ConnectionError $ SomeException (e :: HttpException)
diff --git a/test/Servant/ClientSpec.hs b/test/Servant/ClientSpec.hs
--- a/test/Servant/ClientSpec.hs
+++ b/test/Servant/ClientSpec.hs
@@ -1,48 +1,74 @@
-{-# LANGUAGE CPP                #-}
-{-# LANGUAGE DataKinds          #-}
-{-# LANGUAGE DeriveGeneric      #-}
-{-# LANGUAGE FlexibleContexts   #-}
-{-# LANGUAGE GADTs              #-}
-{-# LANGUAGE OverloadedStrings  #-}
-{-# LANGUAGE RecordWildCards    #-}
-{-# LANGUAGE StandaloneDeriving #-}
-{-# LANGUAGE TypeOperators      #-}
+{-# LANGUAGE CPP                    #-}
+{-# LANGUAGE ConstraintKinds        #-}
+{-# LANGUAGE DataKinds              #-}
+{-# LANGUAGE DeriveGeneric          #-}
+{-# LANGUAGE FlexibleContexts       #-}
+{-# LANGUAGE FlexibleInstances      #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE GADTs                  #-}
+{-# LANGUAGE MultiParamTypeClasses  #-}
+{-# LANGUAGE OverloadedStrings      #-}
+{-# LANGUAGE PolyKinds              #-}
+{-# LANGUAGE RecordWildCards        #-}
+{-# LANGUAGE StandaloneDeriving     #-}
+{-# LANGUAGE ScopedTypeVariables    #-}
+{-# LANGUAGE TypeFamilies           #-}
+{-# LANGUAGE TypeOperators          #-}
+{-# LANGUAGE UndecidableInstances   #-}
 {-# OPTIONS_GHC -fcontext-stack=100 #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
 
+#include "overlapping-compat.h"
 module Servant.ClientSpec where
 
 #if !MIN_VERSION_base(4,8,0)
-import           Control.Applicative         ((<$>))
+import           Control.Applicative        ((<$>))
 #endif
-import qualified Control.Arrow              as Arrow
-import           Control.Concurrent
-import           Control.Exception
-import           Control.Monad.Trans.Either
+import           Control.Arrow              (left)
+import           Control.Concurrent         (forkIO, killThread, ThreadId)
+import           Control.Exception          (bracket)
+import           Control.Monad.Trans.Except (ExceptT, runExceptT, throwE)
 import           Data.Aeson
-import           Data.ByteString.Lazy       (ByteString)
-import           Data.Char
+import           Data.Char                  (chr, isPrint)
 import           Data.Foldable              (forM_)
-import           Data.Monoid
+import           Data.Monoid                hiding (getLast)
 import           Data.Proxy
 import qualified Data.Text                  as T
-import           GHC.Generics
+import           GHC.Generics               (Generic)
+import           GHC.TypeLits
 import qualified Network.HTTP.Client        as C
 import           Network.HTTP.Media
-import           Network.HTTP.Types         hiding (Header)
-import qualified Network.HTTP.Types         as HTTP
+import           Network.HTTP.Types         (Status (..), badRequest400,
+                                             methodGet, ok200, status400)
 import           Network.Socket
-import           Network.Wai                hiding (Response)
+import           Network.Wai                (Application, Request,
+                                             requestHeaders, responseLBS)
 import           Network.Wai.Handler.Warp
+import           System.IO.Unsafe           (unsafePerformIO)
 import           Test.Hspec
 import           Test.Hspec.QuickCheck
 import           Test.HUnit
 import           Test.QuickCheck
 
 import           Servant.API
+import           Servant.API.Internal.Test.ComprehensiveAPI
 import           Servant.Client
 import           Servant.Server
+import           Servant.Server.Experimental.Auth
+import qualified Servant.Common.Req         as SCR
 
+-- This declaration simply checks that all instances are in place.
+_ = client comprehensiveAPI
+
+spec :: Spec
+spec = describe "Servant.Client" $ do
+    sucessSpec
+    failSpec
+    wrappedApiSpec
+    basicAuthSpec
+    genAuthSpec
+
 -- * test data types
 
 data Person = Person {
@@ -68,11 +94,6 @@
         a <- lookupEither "age" xs
         return $ Person (T.unpack n) (read $ T.unpack a)
 
-deriving instance Eq ServantError
-
-instance Eq C.HttpException where
-  a == b = show a == show b
-
 alice :: Person
 alice = Person "Alice" 42
 
@@ -80,15 +101,12 @@
 
 type Api =
        "get" :> Get '[JSON] Person
-  :<|> "deleteEmpty" :> Delete '[] ()
+  :<|> "deleteEmpty" :> DeleteNoContent '[JSON] NoContent
   :<|> "capture" :> Capture "name" String :> Get '[JSON,FormUrlEncoded] Person
   :<|> "body" :> ReqBody '[FormUrlEncoded,JSON] Person :> Post '[JSON] Person
   :<|> "param" :> QueryParam "name" String :> Get '[FormUrlEncoded,JSON] Person
   :<|> "params" :> QueryParams "names" String :> Get '[JSON] [Person]
   :<|> "flag" :> QueryFlag "flag" :> Get '[JSON] Bool
-  :<|> "matrixparam" :> MatrixParam "name" String :> Get '[JSON] Person
-  :<|> "matrixparams" :> MatrixParams "name" String :> Get '[JSON] [Person]
-  :<|> "matrixflag" :> MatrixFlag "flag" :> Get '[JSON] Bool
   :<|> "rawSuccess" :> Raw
   :<|> "rawFailure" :> Raw
   :<|> "multiple" :>
@@ -98,37 +116,29 @@
             ReqBody '[JSON] [(String, [Rational])] :>
             Get '[JSON] (String, Maybe Int, Bool, [(String, [Rational])])
   :<|> "headers" :> Get '[JSON] (Headers TestHeaders Bool)
-  :<|> "deleteContentType" :> Delete '[JSON] ()
+  :<|> "deleteContentType" :> DeleteNoContent '[JSON] NoContent
 api :: Proxy Api
 api = Proxy
 
 server :: Application
 server = serve api (
        return alice
-  :<|> return ()
+  :<|> return NoContent
   :<|> (\ name -> return $ Person name 0)
   :<|> return
   :<|> (\ name -> case name of
                    Just "alice" -> return alice
-                   Just name -> left $ ServantErr 400 (name ++ " not found") "" []
-                   Nothing -> left $ ServantErr 400 "missing parameter" "" [])
-  :<|> (\ names -> return (zipWith Person names [0..]))
-  :<|> return
-  :<|> (\ name -> case name of
-                   Just "alice" -> return alice
-                   Just name -> left $ ServantErr 400 (name ++ " not found") "" []
-                   Nothing -> left $ ServantErr 400 "missing parameter" "" [])
+                   Just n -> throwE $ ServantErr 400 (n ++ " not found") "" []
+                   Nothing -> throwE $ ServantErr 400 "missing parameter" "" [])
   :<|> (\ names -> return (zipWith Person names [0..]))
   :<|> return
   :<|> (\ _request respond -> respond $ responseLBS ok200 [] "rawSuccess")
   :<|> (\ _request respond -> respond $ responseLBS badRequest400 [] "rawFailure")
   :<|> (\ a b c d -> return (a, b, c, d))
   :<|> (return $ addHeader 1729 $ addHeader "eg2" True)
-  :<|> return ()
+  :<|> return NoContent
  )
 
-withServer :: (BaseUrl -> IO a) -> IO a
-withServer action = withWaiDaemon (return server) action
 
 type FailApi =
        "get" :> Raw
@@ -144,93 +154,101 @@
   :<|> (\_request respond -> respond $ responseLBS ok200 [("content-type", "fooooo")] "")
  )
 
-withFailServer :: (BaseUrl -> IO a) -> IO a
-withFailServer action = withWaiDaemon (return failServer) action
+-- * basic auth stuff
 
-spec :: IO ()
-spec = withServer $ \ baseUrl -> do
-  let getGet :: EitherT ServantError IO Person
-      getDeleteEmpty :: EitherT ServantError IO ()
-      getCapture :: String -> EitherT ServantError IO Person
-      getBody :: Person -> EitherT ServantError IO Person
-      getQueryParam :: Maybe String -> EitherT ServantError IO Person
-      getQueryParams :: [String] -> EitherT ServantError IO [Person]
-      getQueryFlag :: Bool -> EitherT ServantError IO Bool
-      getMatrixParam :: Maybe String -> EitherT ServantError IO Person
-      getMatrixParams :: [String] -> EitherT ServantError IO [Person]
-      getMatrixFlag :: Bool -> EitherT ServantError IO Bool
-      getRawSuccess :: Method -> EitherT ServantError IO (Int, ByteString, MediaType, [HTTP.Header], C.Response ByteString)
-      getRawFailure :: Method -> EitherT ServantError IO (Int, ByteString, MediaType, [HTTP.Header], C.Response ByteString)
-      getMultiple :: String -> Maybe Int -> Bool -> [(String, [Rational])] -> EitherT ServantError IO (String, Maybe Int, Bool, [(String, [Rational])])
-      getRespHeaders :: EitherT ServantError IO (Headers TestHeaders Bool)
-      getDeleteContentType :: EitherT ServantError IO ()
-      (     getGet
-       :<|> getDeleteEmpty
-       :<|> getCapture
-       :<|> getBody
-       :<|> getQueryParam
-       :<|> getQueryParams
-       :<|> getQueryFlag
-       :<|> getMatrixParam
-       :<|> getMatrixParams
-       :<|> getMatrixFlag
-       :<|> getRawSuccess
-       :<|> getRawFailure
-       :<|> getMultiple
-       :<|> getRespHeaders
-       :<|> getDeleteContentType)
-         = client api baseUrl
+type BasicAuthAPI =
+       BasicAuth "foo-realm" () :> "private" :> "basic" :> Get '[JSON] Person
 
-  hspec $ do
-    it "Servant.API.Get" $ do
-      (Arrow.left show <$> runEitherT getGet) `shouldReturn` Right alice
+basicAuthAPI :: Proxy BasicAuthAPI
+basicAuthAPI = Proxy
 
-    describe "Servant.API.Delete" $ do
-      it "allows empty content type" $ do
-        (Arrow.left show <$> runEitherT getDeleteEmpty) `shouldReturn` Right ()
+basicAuthHandler :: BasicAuthCheck ()
+basicAuthHandler =
+  let check (BasicAuthData username password) =
+        if username == "servant" && password == "server"
+        then return (Authorized ())
+        else return Unauthorized
+  in BasicAuthCheck check
 
-      it "allows content type" $ do
-        (Arrow.left show <$> runEitherT getDeleteContentType) `shouldReturn` Right ()
+basicServerContext :: Context '[ BasicAuthCheck () ]
+basicServerContext = basicAuthHandler :. EmptyContext
 
-    it "Servant.API.Capture" $ do
-      (Arrow.left show <$> runEitherT (getCapture "Paula")) `shouldReturn` Right (Person "Paula" 0)
+basicAuthServer :: Application
+basicAuthServer = serveWithContext basicAuthAPI basicServerContext (const (return alice))
 
-    it "Servant.API.ReqBody" $ do
-      let p = Person "Clara" 42
-      (Arrow.left show <$> runEitherT (getBody p)) `shouldReturn` Right p
+-- * general auth stuff
 
-    it "Servant.API.QueryParam" $ do
-      Arrow.left show <$> runEitherT (getQueryParam (Just "alice")) `shouldReturn` Right alice
-      Left FailureResponse{..} <- runEitherT (getQueryParam (Just "bob"))
-      responseStatus `shouldBe` Status 400 "bob not found"
+type GenAuthAPI =
+  AuthProtect "auth-tag" :> "private" :> "auth" :> Get '[JSON] Person
 
-    it "Servant.API.QueryParam.QueryParams" $ do
-      (Arrow.left show <$> runEitherT (getQueryParams [])) `shouldReturn` Right []
-      (Arrow.left show <$> runEitherT (getQueryParams ["alice", "bob"]))
-        `shouldReturn` Right [Person "alice" 0, Person "bob" 1]
+genAuthAPI :: Proxy GenAuthAPI
+genAuthAPI = Proxy
 
-    context "Servant.API.QueryParam.QueryFlag" $
-      forM_ [False, True] $ \ flag ->
-      it (show flag) $ do
-        (Arrow.left show <$> runEitherT (getQueryFlag flag)) `shouldReturn` Right flag
+type instance AuthServerData (AuthProtect "auth-tag") = ()
+type instance AuthClientData (AuthProtect "auth-tag") = ()
 
-    it "Servant.API.MatrixParam" $ do
-      Arrow.left show <$> runEitherT (getMatrixParam (Just "alice")) `shouldReturn` Right alice
-      Left FailureResponse{..} <- runEitherT (getMatrixParam (Just "bob"))
+genAuthHandler :: AuthHandler Request ()
+genAuthHandler =
+  let handler req = case lookup "AuthHeader" (requestHeaders req) of
+        Nothing -> throwE (err401 { errBody = "Missing auth header" })
+        Just _ -> return ()
+  in mkAuthHandler handler
+
+genAuthServerContext :: Context '[ AuthHandler Request () ]
+genAuthServerContext = genAuthHandler :. EmptyContext
+
+genAuthServer :: Application
+genAuthServer = serveWithContext genAuthAPI genAuthServerContext (const (return alice))
+
+{-# NOINLINE manager #-}
+manager :: C.Manager
+manager = unsafePerformIO $ C.newManager C.defaultManagerSettings
+
+sucessSpec :: Spec
+sucessSpec = beforeAll (startWaiApp server) $ afterAll endWaiApp $ do
+
+    it "Servant.API.Get" $ \(_, baseUrl) -> do
+      let getGet = getNth (Proxy :: Proxy 0) $ client api baseUrl manager
+      (left show <$> runExceptT getGet) `shouldReturn` Right alice
+
+    describe "Servant.API.Delete" $ do
+      it "allows empty content type" $ \(_, baseUrl) -> do
+        let getDeleteEmpty = getNth (Proxy :: Proxy 1) $ client api baseUrl manager
+        (left show <$> runExceptT getDeleteEmpty) `shouldReturn` Right NoContent
+
+      it "allows content type" $ \(_, baseUrl) -> do
+        let getDeleteContentType = getLast $ client api baseUrl manager
+        (left show <$> runExceptT getDeleteContentType) `shouldReturn` Right NoContent
+
+    it "Servant.API.Capture" $ \(_, baseUrl) -> do
+      let getCapture = getNth (Proxy :: Proxy 2) $ client api baseUrl manager
+      (left show <$> runExceptT (getCapture "Paula")) `shouldReturn` Right (Person "Paula" 0)
+
+    it "Servant.API.ReqBody" $ \(_, baseUrl) -> do
+      let p = Person "Clara" 42
+          getBody = getNth (Proxy :: Proxy 3) $ client api baseUrl manager
+      (left show <$> runExceptT (getBody p)) `shouldReturn` Right p
+
+    it "Servant.API.QueryParam" $ \(_, baseUrl) -> do
+      let getQueryParam = getNth (Proxy :: Proxy 4) $ client api baseUrl manager
+      left show <$> runExceptT (getQueryParam (Just "alice")) `shouldReturn` Right alice
+      Left FailureResponse{..} <- runExceptT (getQueryParam (Just "bob"))
       responseStatus `shouldBe` Status 400 "bob not found"
 
-    it "Servant.API.MatrixParam.MatrixParams" $ do
-      Arrow.left show <$> runEitherT (getMatrixParams []) `shouldReturn` Right []
-      Arrow.left show <$> runEitherT (getMatrixParams ["alice", "bob"])
+    it "Servant.API.QueryParam.QueryParams" $ \(_, baseUrl) -> do
+      let getQueryParams = getNth (Proxy :: Proxy 5) $ client api baseUrl manager
+      (left show <$> runExceptT (getQueryParams [])) `shouldReturn` Right []
+      (left show <$> runExceptT (getQueryParams ["alice", "bob"]))
         `shouldReturn` Right [Person "alice" 0, Person "bob" 1]
 
-    context "Servant.API.MatrixParam.MatrixFlag" $
-      forM_ [False, True] $ \ flag ->
-      it (show flag) $ do
-        Arrow.left show <$> runEitherT (getMatrixFlag flag) `shouldReturn` Right flag
+    context "Servant.API.QueryParam.QueryFlag" $
+      forM_ [False, True] $ \ flag -> it (show flag) $ \(_, baseUrl) -> do
+        let getQueryFlag = getNth (Proxy :: Proxy 6) $ client api baseUrl manager
+        (left show <$> runExceptT (getQueryFlag flag)) `shouldReturn` Right flag
 
-    it "Servant.API.Raw on success" $ do
-      res <- runEitherT (getRawSuccess methodGet)
+    it "Servant.API.Raw on success" $ \(_, baseUrl) -> do
+      let getRawSuccess = getNth (Proxy :: Proxy 7) $ client api baseUrl manager
+      res <- runExceptT (getRawSuccess methodGet)
       case res of
         Left e -> assertFailure $ show e
         Right (code, body, ct, _, response) -> do
@@ -238,133 +256,141 @@
           C.responseBody response `shouldBe` body
           C.responseStatus response `shouldBe` ok200
 
-    it "Servant.API.Raw on failure" $ do
-      res <- runEitherT (getRawFailure methodGet)
+    it "Servant.API.Raw should return a Left in case of failure" $ \(_, baseUrl) -> do
+      let getRawFailure = getNth (Proxy :: Proxy 8) $ client api baseUrl manager
+      res <- runExceptT (getRawFailure methodGet)
       case res of
-        Left e -> assertFailure $ show e
-        Right (code, body, ct, _, response) -> do
-          (code, body, ct) `shouldBe` (400, "rawFailure", "application"//"octet-stream")
-          C.responseBody response `shouldBe` body
-          C.responseStatus response `shouldBe` badRequest400
+        Right _ -> assertFailure "expected Left, but got Right"
+        Left e -> do
+          Servant.Client.responseStatus e `shouldBe` status400
+          Servant.Client.responseBody e `shouldBe` "rawFailure"
 
-    it "Returns headers appropriately" $ withServer $ \ _ -> do
-      res <- runEitherT getRespHeaders
+    it "Returns headers appropriately" $ \(_, baseUrl) -> do
+      let getRespHeaders = getNth (Proxy :: Proxy 10) $ client api baseUrl manager
+      res <- runExceptT getRespHeaders
       case res of
         Left e -> assertFailure $ show e
         Right val -> getHeaders val `shouldBe` [("X-Example1", "1729"), ("X-Example2", "eg2")]
 
     modifyMaxSuccess (const 20) $ do
-      it "works for a combination of Capture, QueryParam, QueryFlag and ReqBody" $
-        property $ forAllShrink pathGen shrink $ \(NonEmpty cap) num flag body ->
+      it "works for a combination of Capture, QueryParam, QueryFlag and ReqBody" $ \(_, baseUrl) ->
+        let getMultiple = getNth (Proxy :: Proxy 9) $ client api baseUrl manager
+        in property $ forAllShrink pathGen shrink $ \(NonEmpty cap) num flag body ->
           ioProperty $ do
-            result <- Arrow.left show <$> runEitherT (getMultiple cap num flag body)
+            result <- left show <$> runExceptT (getMultiple cap num flag body)
             return $
               result === Right (cap, num, flag, body)
 
 
-    context "client correctly handles error status codes" $ do
-      let test :: (WrappedApi, String) -> Spec
-          test (WrappedApi api, desc) =
-            it desc $
-            withWaiDaemon (return (serve api (left $ ServantErr 500 "error message" "" []))) $
-            \ host -> do
-              let getResponse :: EitherT ServantError IO ()
-                  getResponse = client api host
-              Left FailureResponse{..} <- runEitherT getResponse
-              responseStatus `shouldBe` (Status 500 "error message")
-      mapM_ test $
+wrappedApiSpec :: Spec
+wrappedApiSpec = describe "error status codes" $ do
+  let serveW api = serve api $ throwE $ ServantErr 500 "error message" "" []
+  context "are correctly handled by the client" $
+    let test :: (WrappedApi, String) -> Spec
+        test (WrappedApi api, desc) =
+          it desc $ bracket (startWaiApp $ serveW api) endWaiApp $ \(_, baseUrl) -> do
+            let getResponse :: ExceptT ServantError IO ()
+                getResponse = client api baseUrl manager
+            Left FailureResponse{..} <- runExceptT getResponse
+            responseStatus `shouldBe` (Status 500 "error message")
+    in mapM_ test $
         (WrappedApi (Proxy :: Proxy (Delete '[JSON] ())), "Delete") :
         (WrappedApi (Proxy :: Proxy (Get '[JSON] ())), "Get") :
         (WrappedApi (Proxy :: Proxy (Post '[JSON] ())), "Post") :
         (WrappedApi (Proxy :: Proxy (Put '[JSON] ())), "Put") :
         []
 
-failSpec :: IO ()
-failSpec = withFailServer $ \ baseUrl -> do
-  let getGet :: EitherT ServantError IO Person
-      getDeleteEmpty :: EitherT ServantError IO ()
-      getCapture :: String -> EitherT ServantError IO Person
-      getBody :: Person -> EitherT ServantError IO Person
-      (     getGet
-       :<|> getDeleteEmpty
-       :<|> getCapture
-       :<|> getBody
-       :<|> _ )
-         = client api baseUrl
-      getGetWrongHost :: EitherT ServantError IO Person
-      (getGetWrongHost :<|> _) = client api (BaseUrl Http "127.0.0.1" 19872)
+failSpec :: Spec
+failSpec = beforeAll (startWaiApp failServer) $ afterAll endWaiApp $ do
 
-  hspec $ do
     context "client returns errors appropriately" $ do
-      it "reports FailureResponse" $ do
-        Left res <- runEitherT getDeleteEmpty
+      it "reports FailureResponse" $ \(_, baseUrl) -> do
+        let (_ :<|> getDeleteEmpty :<|> _) = client api baseUrl manager
+        Left res <- runExceptT getDeleteEmpty
         case res of
           FailureResponse (Status 404 "Not Found") _ _ -> return ()
           _ -> fail $ "expected 404 response, but got " <> show res
 
-      it "reports DecodeFailure" $ do
-        Left res <- runEitherT (getCapture "foo")
+      it "reports DecodeFailure" $ \(_, baseUrl) -> do
+        let (_ :<|> _ :<|> getCapture :<|> _) = client api baseUrl manager
+        Left res <- runExceptT (getCapture "foo")
         case res of
           DecodeFailure _ ("application/json") _ -> return ()
           _ -> fail $ "expected DecodeFailure, but got " <> show res
 
-      it "reports ConnectionError" $ do
-        Left res <- runEitherT getGetWrongHost
+      it "reports ConnectionError" $ \_ -> do
+        let (getGetWrongHost :<|> _) = client api (BaseUrl Http "127.0.0.1" 19872 "") manager
+        Left res <- runExceptT getGetWrongHost
         case res of
-          ConnectionError (C.FailedConnectionException2 "127.0.0.1" 19872 False _) -> return ()
+          ConnectionError _ -> return ()
           _ -> fail $ "expected ConnectionError, but got " <> show res
 
-      it "reports UnsupportedContentType" $ do
-        Left res <- runEitherT getGet
+      it "reports UnsupportedContentType" $ \(_, baseUrl) -> do
+        let (getGet :<|> _ ) = client api baseUrl manager
+        Left res <- runExceptT getGet
         case res of
           UnsupportedContentType ("application/octet-stream") _ -> return ()
           _ -> fail $ "expected UnsupportedContentType, but got " <> show res
 
-      it "reports InvalidContentTypeHeader" $ do
-        Left res <- runEitherT (getBody alice)
+      it "reports InvalidContentTypeHeader" $ \(_, baseUrl) -> do
+        let (_ :<|> _ :<|> _ :<|> getBody :<|> _) = client api baseUrl manager
+        Left res <- runExceptT (getBody alice)
         case res of
           InvalidContentTypeHeader "fooooo" _ -> return ()
           _ -> fail $ "expected InvalidContentTypeHeader, but got " <> show res
 
 data WrappedApi where
-  WrappedApi :: (HasServer api, Server api ~ EitherT ServantErr IO a,
-                 HasClient api, Client api ~ EitherT ServantError IO ()) =>
+  WrappedApi :: (HasServer (api :: *) '[], Server api ~ ExceptT ServantErr IO a,
+                 HasClient api, Client api ~ ExceptT ServantError IO ()) =>
     Proxy api -> WrappedApi
 
+basicAuthSpec :: Spec
+basicAuthSpec = beforeAll (startWaiApp basicAuthServer) $ afterAll endWaiApp $ do
+  context "Authentication works when requests are properly authenticated" $ do
 
+    it "Authenticates a BasicAuth protected server appropriately" $ \(_,baseUrl) -> do
+      let getBasic = client basicAuthAPI baseUrl manager
+      let basicAuthData = BasicAuthData "servant" "server"
+      (left show <$> runExceptT (getBasic basicAuthData)) `shouldReturn` Right alice
+
+  context "Authentication is rejected when requests are not authenticated properly" $ do
+
+    it "Authenticates a BasicAuth protected server appropriately" $ \(_,baseUrl) -> do
+      let getBasic = client basicAuthAPI baseUrl manager
+      let basicAuthData = BasicAuthData "not" "password"
+      Left FailureResponse{..} <- runExceptT (getBasic basicAuthData)
+      responseStatus `shouldBe` Status 403 "Forbidden"
+
+genAuthSpec :: Spec
+genAuthSpec = beforeAll (startWaiApp genAuthServer) $ afterAll endWaiApp $ do
+  context "Authentication works when requests are properly authenticated" $ do
+
+    it "Authenticates a AuthProtect protected server appropriately" $ \(_, baseUrl) -> do
+      let getProtected = client genAuthAPI baseUrl manager
+      let authRequest = mkAuthenticateReq () (\_ req ->  SCR.addHeader "AuthHeader" ("cool" :: String) req)
+      (left show <$> runExceptT (getProtected authRequest)) `shouldReturn` Right alice
+
+  context "Authentication is rejected when requests are not authenticated properly" $ do
+
+    it "Authenticates a AuthProtect protected server appropriately" $ \(_, baseUrl) -> do
+      let getProtected = client genAuthAPI baseUrl manager
+      let authRequest = mkAuthenticateReq () (\_ req ->  SCR.addHeader "Wrong" ("header" :: String) req)
+      Left FailureResponse{..} <- runExceptT (getProtected authRequest)
+      responseStatus `shouldBe` (Status 401 "Unauthorized")
+
 -- * utils
 
-withWaiDaemon :: IO Application -> (BaseUrl -> IO a) -> IO a
-withWaiDaemon mkApplication action = do
-  application <- mkApplication
-  bracket (acquire application) free (\ (_, _, baseUrl) -> action baseUrl)
- where
-  acquire application = do
-    (notifyStart, waitForStart) <- lvar
-    (notifyKilled, waitForKilled) <- lvar
-    thread <- forkIO $ (do
-      (krakenPort, socket) <- openTestSocket
-      let settings =
-            setPort krakenPort $ -- set here just for consistency, shouldn't be
-                                 -- used (it's set in the socket)
-            setBeforeMainLoop (notifyStart krakenPort)
-            defaultSettings
-      runSettingsSocket settings socket application)
-            `finally` notifyKilled ()
-    krakenPort <- waitForStart
-    let baseUrl = (BaseUrl Http "localhost" 80){baseUrlPort = krakenPort}
-    return (thread, waitForKilled, baseUrl)
-  free (thread, waitForKilled, _) = do
-    killThread thread
-    waitForKilled
+startWaiApp :: Application -> IO (ThreadId, BaseUrl)
+startWaiApp app = do
+    (port, socket) <- openTestSocket
+    let settings = setPort port $ defaultSettings
+    thread <- forkIO $ runSettingsSocket settings socket app
+    return (thread, BaseUrl Http "localhost" port "")
 
-  lvar :: IO (a -> IO (), IO a)
-  lvar = do
-    mvar <- newEmptyMVar
-    let put = putMVar mvar
-        wait = readMVar mvar
-    return (put, wait)
 
+endWaiApp :: (ThreadId, BaseUrl) -> IO ()
+endWaiApp (thread, _) = killThread thread
+
 openTestSocket :: IO (Port, Socket)
 openTestSocket = do
   s <- socket AF_INET Stream defaultProtocol
@@ -381,3 +407,25 @@
     filter (not . (`elem` ("?%[]/#;" :: String))) $
     filter isPrint $
     map chr [0..127]
+
+class GetNth (n :: Nat) a b | n a -> b where
+    getNth :: Proxy n -> a -> b
+
+instance OVERLAPPING_
+  GetNth 0 (x :<|> y) x where
+      getNth _ (x :<|> _) = x
+
+instance OVERLAPPING_
+  (GetNth (n - 1) x y) => GetNth n (a :<|> x) y where
+      getNth _ (_ :<|> x) = getNth (Proxy :: Proxy (n - 1)) x
+
+class GetLast a b | a -> b where
+    getLast :: a -> b
+
+instance OVERLAPPING_
+  (GetLast b c) => GetLast (a :<|> b) c where
+      getLast (_ :<|> b) = getLast b
+
+instance OVERLAPPING_
+  GetLast a a where
+      getLast a = a
diff --git a/test/Servant/Common/BaseUrlSpec.hs b/test/Servant/Common/BaseUrlSpec.hs
--- a/test/Servant/Common/BaseUrlSpec.hs
+++ b/test/Servant/Common/BaseUrlSpec.hs
@@ -1,72 +1,85 @@
-{-# LANGUAGE CPP                  #-}
+{-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Servant.Common.BaseUrlSpec where
 
 #if !MIN_VERSION_base(4,8,0)
-import Control.Applicative
+import           Control.Applicative
 #endif
-import Control.DeepSeq
-import Test.Hspec
-import Test.QuickCheck
+import           Control.DeepSeq
+import           Test.Hspec
+import           Test.QuickCheck
 
-import Servant.Common.BaseUrl
+import           Servant.Common.BaseUrl
 
 spec :: Spec
 spec = do
+  let parse = parseBaseUrl :: String -> Maybe BaseUrl
   describe "showBaseUrl" $ do
     it "shows a BaseUrl" $ do
-      showBaseUrl (BaseUrl Http "foo.com" 80) `shouldBe` "http://foo.com"
-
+      showBaseUrl (BaseUrl Http "foo.com" 80 "") `shouldBe` "http://foo.com"
     it "shows a https BaseUrl" $ do
-      showBaseUrl (BaseUrl Https "foo.com" 443) `shouldBe` "https://foo.com"
+      showBaseUrl (BaseUrl Https "foo.com" 443 "") `shouldBe` "https://foo.com"
+    it "shows the path of a BaseUrl" $ do
+      showBaseUrl (BaseUrl Http "foo.com" 80 "api") `shouldBe` "http://foo.com/api"
+    it "shows the path of an https BaseUrl" $ do
+      showBaseUrl (BaseUrl Https "foo.com" 443 "api") `shouldBe` "https://foo.com/api"
+    it "handles leading slashes in path" $ do
+      showBaseUrl (BaseUrl Https "foo.com" 443 "/api") `shouldBe` "https://foo.com/api"
 
   describe "httpBaseUrl" $ do
     it "allows to construct default http BaseUrls" $ do
-      BaseUrl Http "bar" 80 `shouldBe` BaseUrl Http "bar" 80
+      BaseUrl Http "bar" 80 "" `shouldBe` BaseUrl Http "bar" 80 ""
 
   describe "parseBaseUrl" $ do
     it "is total" $ do
       property $ \ string ->
-        deepseq (fmap show (parseBaseUrl string)) True
+        deepseq (fmap show (parse string )) True
 
     it "is the inverse of showBaseUrl" $ do
-      property $ \ baseUrl ->
-        counterexample (showBaseUrl baseUrl) $
-        parseBaseUrl (showBaseUrl baseUrl) ===
-          Right baseUrl
+      property $ \ baseUrl -> counterexample (showBaseUrl baseUrl) $
+        parse (showBaseUrl baseUrl) === Just baseUrl
 
-    it "allows trailing slashes" $ do
-      parseBaseUrl "foo.com/" `shouldBe` Right (BaseUrl Http "foo.com" 80)
+    context "trailing slashes" $ do
+      it "allows trailing slashes" $ do
+        parse "foo.com/" `shouldBe` Just (BaseUrl Http "foo.com" 80 "")
 
+      it "allows trailing slashes in paths" $ do
+        parse "foo.com/api/" `shouldBe` Just (BaseUrl Http "foo.com" 80 "api")
+
     context "urls without scheme" $ do
       it "assumes http" $ do
-        parseBaseUrl "foo.com" `shouldBe` Right (BaseUrl Http "foo.com" 80)
+        parse "foo.com" `shouldBe` Just (BaseUrl Http "foo.com" 80 "")
 
       it "allows port numbers" $ do
-        parseBaseUrl "foo.com:8080" `shouldBe` Right (BaseUrl Http "foo.com" 8080)
+        parse "foo.com:8080" `shouldBe` Just (BaseUrl Http "foo.com" 8080 "")
 
+    it "can parse paths" $ do
+      parse "http://foo.com/api" `shouldBe` Just (BaseUrl Http "foo.com" 80 "api")
+
     it "rejects ftp urls" $ do
-      parseBaseUrl "ftp://foo.com" `shouldSatisfy` isLeft
+      parse "ftp://foo.com" `shouldBe` Nothing
 
 instance Arbitrary BaseUrl where
   arbitrary = BaseUrl <$>
     elements [Http, Https] <*>
     hostNameGen <*>
-    portGen
+    portGen <*>
+    pathGen
    where
+    letters = ['a' .. 'z'] ++ ['A' .. 'Z']
     -- this does not perfectly mirror the url standard, but I hope it's good
     -- enough.
     hostNameGen = do
-      let letters = ['a' .. 'z'] ++ ['A' .. 'Z']
       first <- elements letters
       middle <- listOf1 $ elements (letters ++ ['0' .. '9'] ++ ['.', '-'])
-      last <- elements letters
-      return (first : middle ++ [last])
+      last' <- elements letters
+      return (first : middle ++ [last'])
     portGen = frequency $
       (1, return 80) :
       (1, return 443) :
       (1, choose (1, 20000)) :
       []
+    pathGen = listOf1 . elements $ letters
 
 isLeft :: Either a b -> Bool
 isLeft = either (const True) (const False)
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,7 +1,1 @@
-import Servant.ClientSpec (spec, failSpec)
-
-main :: IO ()
-main = do
-  spec
-  failSpec
-
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
