diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,12 @@
 
 ## [Unreleased]
 
+## [0.4.0] - 2020-01-10
+
+- #249 Serve nar content
+- #247 Generalize auth to just JWTs
+- NarC -> NarFileName
+
 ## [0.3.0] - 2019-09-03
 
 - #216 Add bulk store path query
diff --git a/cachix-api.cabal b/cachix-api.cabal
--- a/cachix-api.cabal
+++ b/cachix-api.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               cachix-api
-version:            0.3.0
+version: 0.4.0
 synopsis:           Servant HTTP API specification for https://cachix.org
 homepage:           https://github.com/cachix/cachix#readme
 bug-reports:        https://github.com/cachix/cachix/issues
@@ -16,6 +16,7 @@
 
 common defaults
   default-extensions:
+    NoImplicitPrelude
     DeriveAnyClass
     DeriveGeneric
     OverloadedStrings
@@ -42,7 +43,9 @@
     Cachix.Types.BinaryCacheAuthenticated
     Cachix.Types.BinaryCacheCreate
     Cachix.Types.ContentTypes
+    Cachix.Types.CreateToken
     Cachix.Types.GitHubTeam
+    Cachix.Types.NarFileName
     Cachix.Types.NarInfoCreate
     Cachix.Types.Servant
     Cachix.Types.Session
@@ -62,8 +65,10 @@
     , exceptions
     , http-api-data
     , http-media
+    , jose
     , lens
     , memory
+    , protolude
     , resourcet
     , servant               >=0.14.1
     , servant-auth
@@ -84,6 +89,7 @@
     , aeson
     , base        >=4.7 && <5
     , cachix-api
+    , protolude
 
 test-suite cachix-api-test
   import:             defaults
diff --git a/cachix-gen-swagger/Main.hs b/cachix-gen-swagger/Main.hs
--- a/cachix-gen-swagger/Main.hs
+++ b/cachix-gen-swagger/Main.hs
@@ -2,6 +2,7 @@
 
 import Cachix.Api (swaggerDoc)
 import Data.Aeson (encode)
+import Protolude
 
 main :: IO ()
 main = print $ encode swaggerDoc
diff --git a/src/Cachix/Api.hs b/src/Cachix/Api.hs
--- a/src/Cachix/Api.hs
+++ b/src/Cachix/Api.hs
@@ -14,15 +14,18 @@
     BinaryCacheStreamingAPI (..),
     BinaryCachStreamingServantAPI,
     module Cachix.Api.Types,
-    module Cachix.Types.ContentTypes
-    )
+    module Cachix.Types.ContentTypes,
+    module Cachix.Types.NarFileName,
+  )
 where
 
 import Cachix.Api.Types
 import qualified Cachix.Types.BinaryCacheAuthenticated as BinaryCacheAuthenticated
 import qualified Cachix.Types.BinaryCacheCreate as BinaryCacheCreate
 import Cachix.Types.ContentTypes
+import qualified Cachix.Types.CreateToken as CreateToken
 import qualified Cachix.Types.GitHubTeam as GitHubTeam
+import Cachix.Types.NarFileName (NarFileName (..))
 import qualified Cachix.Types.NarInfoCreate as NarInfoCreate
 import Cachix.Types.Servant (Get302, Head, Post302)
 import Cachix.Types.Session (Session)
@@ -31,11 +34,10 @@
 import Control.Lens
 import Control.Monad.Trans.Resource
 import Data.ByteString (ByteString)
+import qualified Data.ByteString.Lazy as BSL
 import Data.Conduit (ConduitT)
-import Data.Proxy (Proxy (..))
 import Data.Swagger hiding (Header)
-import Data.Text
-import GHC.Generics (Generic)
+import Protolude
 import Servant.API hiding (BasicAuth)
 import Servant.API.Generic
 import Servant.Auth
@@ -47,161 +49,174 @@
 
 data BinaryCacheAPI route
   = BinaryCacheAPI
-      { get
-          :: route
-               :- CachixAuth
-               :> Get '[JSON] BinaryCache,
-        create
-          :: route
-               :- CachixAuth
-               :> ReqBody '[JSON] BinaryCacheCreate.BinaryCacheCreate
-               :> Post '[JSON] NoContent,
+      { get ::
+          route
+            :- CachixAuth
+            :> Get '[JSON] BinaryCache,
+        create ::
+          route
+            :- CachixAuth
+            :> ReqBody '[JSON] BinaryCacheCreate.BinaryCacheCreate
+            :> Post '[JSON] NoContent,
+        delete ::
+          route
+            :- CachixAuth
+            :> Delete '[JSON] NoContent,
         -- https://cache.nixos.org/nix-cache-info
-        nixCacheInfo
-          :: route
-               :- CachixAuth
-               :> "nix-cache-info"
-               :> Get '[XNixCacheInfo, JSON] NixCacheInfo,
+        nixCacheInfo ::
+          route
+            :- CachixAuth
+            :> "nix-cache-info"
+            :> Get '[XNixCacheInfo, JSON] NixCacheInfo,
         -- Hydra: src/lib/Hydra/View/NARInfo.pm
-        narinfo
-          :: route
-               :- CachixAuth
-               :> Capture "narinfo" NarInfoC
-               :> Get '[XNixNarInfo, JSON] NarInfo,
-        narinfoHead
-          :: route
-               :- CachixAuth
-               :> Capture "narinfo" NarInfoC
-               :> Head,
-        narinfoBulk
-          :: route
-               :- CachixAuth
-               :> "narinfo"
-               :> Summary "Given a list of store hashes, return a list of those that are missing"
-               :> ReqBody '[JSON] [Text]
-               :> Post '[JSON] [Text],
-        createNarinfo
-          :: route
-               :- Capture "narinfo" NarInfoC
-               :> ReqBody '[JSON] NarInfoCreate.NarInfoCreate
-               :> Post '[JSON] NoContent,
-        createKey
-          :: route
-               :- CachixAuth
-               :> "key"
-               :> ReqBody '[JSON] SigningKeyCreate.SigningKeyCreate
-               :> Post '[JSON] NoContent
-        }
+        narinfo ::
+          route
+            :- CachixAuth
+            :> Capture "narinfo" NarInfoC
+            :> Get '[XNixNarInfo, JSON] NarInfo,
+        narinfoHead ::
+          route
+            :- CachixAuth
+            :> Capture "narinfo" NarInfoC
+            :> Head,
+        narinfoBulk ::
+          route
+            :- CachixAuth
+            :> "narinfo"
+            :> Summary "Given a list of store hashes, return a list of those that are missing"
+            :> ReqBody '[JSON] [Text]
+            :> Post '[JSON] [Text],
+        createNarinfo ::
+          route
+            :- Capture "narinfo" NarInfoC
+            :> ReqBody '[JSON] NarInfoCreate.NarInfoCreate
+            :> Post '[JSON] NoContent,
+        createKey ::
+          route
+            :- CachixAuth
+            :> "key"
+            :> ReqBody '[JSON] SigningKeyCreate.SigningKeyCreate
+            :> Post '[JSON] NoContent
+      }
   deriving (Generic)
 
 -- | Streaming endpoints
 data BinaryCacheStreamingAPI route
   = BinaryCacheStreamingAPI
       { -- Hydra: src/lib/Hydra/View/NixNAR.pm
-        nar
-          :: route
-               :- CachixAuth
-               :> "nar"
-               :> Capture "nar" NarC
-               :> StreamGet NoFraming OctetStream (ConduitT () ByteString (ResourceT IO) ()),
-        createNar
-          :: route
-               :- "nar"
-               :> StreamBody NoFraming XNixNar (ConduitT () ByteString (ResourceT IO) ())
-               :> Post '[JSON] NoContent
-        }
+        nar ::
+          route
+            :- CachixAuth
+            :> "nar"
+            :> Capture "nar" NarFileName
+            :> StreamGet NoFraming OctetStream (ConduitT () ByteString (ResourceT IO) ()),
+        createNar ::
+          route
+            :- "nar"
+            :> StreamBody NoFraming XNixNar (ConduitT () ByteString (ResourceT IO) ())
+            :> Post '[JSON] NoContent,
+        serveNarContent ::
+          route
+            :- CachixAuth
+            :> "serve"
+            :> Capture "storehash" Text
+            :> CaptureAll "filepath" Text
+            :> Summary "Serve a file from a given store path"
+            :> Get '[OctetStream] (Headers '[Header "X-Content-Type-Options" Text] BSL.ByteString)
+      }
   deriving (Generic)
 
 data InstallAPI route
   = InstallAPI
-      { installGetLatest
-          :: route
-               :- Summary "Redirects to a tarball containing nix expression to build the latest version of cachix cli"
-               :> Get302 '[JSON] '[],
-        installGetVersion
-          :: route
-               :- Summary "Redirects to a tarball containing nix expression to build given version of cachix cli"
-               :> Capture "version" Text
-               :> Get302 '[JSON] '[]
-        }
+      { installGetLatest ::
+          route
+            :- Summary "Redirects to a tarball containing nix expression to build the latest version of cachix cli"
+            :> Get302 '[JSON] '[],
+        installGetVersion ::
+          route
+            :- Summary "Redirects to a tarball containing nix expression to build given version of cachix cli"
+            :> Capture "version" Text
+            :> Get302 '[JSON] '[]
+      }
   deriving (Generic)
 
 data GitHubAPI route
   = GitHubAPI
-      { githubOrganizations
-          :: route
-               :- CachixAuth
-               :> "orgs"
-               :> Get '[JSON] [Text],
-        githubTeams
-          :: route
-               :- CachixAuth
-               :> "orgs"
-               :> Capture "org" Text
-               :> "teams"
-               :> Get '[JSON] [GitHubTeam.GitHubTeam]
-        }
+      { githubOrganizations ::
+          route
+            :- CachixAuth
+            :> "orgs"
+            :> Get '[JSON] [Text],
+        githubTeams ::
+          route
+            :- CachixAuth
+            :> "orgs"
+            :> Capture "org" Text
+            :> "teams"
+            :> Get '[JSON] [GitHubTeam.GitHubTeam]
+      }
   deriving (Generic)
 
 data CachixAPI route
   = CachixAPI
-      { logout
-          :: route
-               :- "logout"
-               :> CachixAuth
-               :> Post302 '[JSON]
-                    '[ Header "Set-Cookie" SetCookie,
-                       Header "Set-Cookie" SetCookie
-                       ],
-        login
-          :: route
-               :- "login"
-               :> Get302 '[JSON] '[],
-        loginCallback
-          :: route
-               :- "login"
-               :> "callback"
-               :> QueryParam "code" Text
-               :> QueryParam "state" Text
-               :> Get302 '[JSON]
-                    '[ Header "Set-Cookie" SetCookie,
-                       Header "Set-Cookie" SetCookie
-                       ],
-        user
-          :: route
-               :- CachixAuth
-               :> "user"
-               :> Get '[JSON] User,
-        createToken
-          :: route
-               :- CachixAuth
-               :> "token"
-               :> Post '[JSON] Text,
-        caches
-          :: route
-               :- CachixAuth
-               :> "cache"
-               :> Get '[JSON] [BinaryCacheAuthenticated.BinaryCacheAuthenticated],
-        cache
-          :: route
-               :- "cache"
-               :> Capture "name" Text
-               :> ToServantApi BinaryCacheAPI,
-        install
-          :: route
-               :- "install"
-               :> ToServantApi InstallAPI,
-        github
-          :: route
-               :- "github"
-               :> ToServantApi GitHubAPI
-        }
+      { logout ::
+          route
+            :- "logout"
+            :> CachixAuth
+            :> Post302 '[JSON]
+                 '[ Header "Set-Cookie" SetCookie,
+                    Header "Set-Cookie" SetCookie
+                  ],
+        login ::
+          route
+            :- "login"
+            :> Get302 '[JSON] '[],
+        loginCallback ::
+          route
+            :- "login"
+            :> "callback"
+            :> QueryParam "code" Text
+            :> QueryParam "state" Text
+            :> Get302 '[JSON]
+                 '[ Header "Set-Cookie" SetCookie,
+                    Header "Set-Cookie" SetCookie
+                  ],
+        user ::
+          route
+            :- CachixAuth
+            :> "user"
+            :> Get '[JSON] User,
+        createToken ::
+          route
+            :- CachixAuth
+            :> "token"
+            :> ReqBody '[JSON] CreateToken.CreateToken
+            :> Post '[JSON] Text,
+        caches ::
+          route
+            :- CachixAuth
+            :> "cache"
+            :> Get '[JSON] [BinaryCacheAuthenticated.BinaryCacheAuthenticated],
+        cache ::
+          route
+            :- "cache"
+            :> Capture "name" Text
+            :> ToServantApi BinaryCacheAPI,
+        install ::
+          route
+            :- "install"
+            :> ToServantApi InstallAPI,
+        github ::
+          route
+            :- "github"
+            :> ToServantApi GitHubAPI
+      }
   deriving (Generic)
 
 type CachixServantAPI = "api" :> "v1" :> ToServantApi CachixAPI
 
-type BinaryCachStreamingServantAPI
-  = "api" :> "v1" :> "cache" :> Capture "name" Text :> ToServantApi BinaryCacheStreamingAPI
+type BinaryCachStreamingServantAPI =
+  "api" :> "v1" :> "cache" :> Capture "name" Text :> ToServantApi BinaryCacheStreamingAPI
 
 servantApi :: Proxy CachixServantAPI
 servantApi = Proxy
diff --git a/src/Cachix/Api/Error.hs b/src/Cachix/Api/Error.hs
--- a/src/Cachix/Api/Error.hs
+++ b/src/Cachix/Api/Error.hs
@@ -1,26 +1,26 @@
 module Cachix.Api.Error
   ( escalate,
-    escalateAs
-    )
+    escalateAs,
+  )
 where
 
 import Control.Exception (Exception)
 import Control.Monad.Catch (MonadThrow (throwM))
-
-{- | Examples:
-    > escalate . maybeToEither err404
+import Protolude
 
-  | Note that exceptions gets handled by warp and logged (user sees just "Internal server")
--}
-escalateAs
-  :: (Exception exc, MonadThrow m)
-  => (l -> exc)
-  -> Either l a
-  -> m a
+-- | Examples:
+--    > escalate . maybeToEither err404
+--
+--  | Note that exceptions gets handled by warp and logged (user sees just "Internal server")
+escalateAs ::
+  (Exception exc, MonadThrow m) =>
+  (l -> exc) ->
+  Either l a ->
+  m a
 escalateAs f = either (throwM . f) pure
 
-escalate
-  :: (Exception exc, MonadThrow m)
-  => Either exc a
-  -> m a
-escalate = escalateAs id
+escalate ::
+  (Exception exc, MonadThrow m) =>
+  Either exc a ->
+  m a
+escalate = escalateAs identity
diff --git a/src/Cachix/Api/Signing.hs b/src/Cachix/Api/Signing.hs
--- a/src/Cachix/Api/Signing.hs
+++ b/src/Cachix/Api/Signing.hs
@@ -2,8 +2,8 @@
   ( fingerprint,
     passthroughSizeSink,
     passthroughHashSinkB16,
-    passthroughHashSink
-    )
+    passthroughHashSink,
+  )
 where
 
 import Control.Monad.IO.Class (MonadIO, liftIO)
@@ -15,17 +15,17 @@
 import Data.Conduit
 import qualified Data.Conduit.Combinators as CC
 import Data.IORef
-import Data.String.Conv (toS)
 import qualified Data.Text as T
-import Data.Text (Text)
+import Protolude
 
 -- perl/lib/Nix/Manifest.pm:fingerprintPath
 -- NB: references must be sorted
 fingerprint :: Text -> Text -> Integer -> [Text] -> ByteString
 fingerprint storePath narHash narSize references =
-  toS
-    $ T.intercalate ";"
-        ["1", storePath, narHash, T.pack (show narSize), T.intercalate "," references]
+  toS $
+    T.intercalate
+      ";"
+      ["1", storePath, narHash, show narSize, T.intercalate "," references]
 
 -- Useful sinks for streaming nars
 sizeSink :: MonadIO m => ConduitT ByteString o m Integer
diff --git a/src/Cachix/Api/Types.hs b/src/Cachix/Api/Types.hs
--- a/src/Cachix/Api/Types.hs
+++ b/src/Cachix/Api/Types.hs
@@ -2,10 +2,9 @@
 
 import Control.DeepSeq (NFData)
 import Data.Aeson (FromJSON, ToJSON)
-import Data.Monoid ((<>))
 import Data.Swagger (ToParamSchema, ToSchema)
-import Data.Text (Text, dropEnd, takeEnd)
-import GHC.Generics (Generic)
+import Data.Text (dropEnd, takeEnd)
+import Protolude
 import Servant.API
 
 data NixCacheInfo
@@ -13,39 +12,39 @@
       { storeDir :: Text,
         wantMassQuery :: Integer,
         priority :: Integer
-        }
+      }
   deriving (Generic, Show, FromJSON, ToJSON, ToSchema)
 
 -- narinfo url includes storePath hash and .narinfo suffix
 data NarInfo
   = NarInfo
-      { storePath :: Text,
-        -- ^ absolute path of the derivation in nix store
+      { -- | absolute path of the derivation in nix store
+        storePath :: Text,
+        -- | relative url (to current domain) to download nar file
         url :: Text,
-        -- ^ relative url (to current domain) to download nar file
+        -- | name of the compression algorithm, eg. xz
         compression :: Text,
-        -- ^ name of the compression algorithm, eg. xz
-        fileHash :: Text,
-        -- ^ sha256 hash of the compressed nar file
+        -- | sha256 hash of the compressed nar file
         -- NOTE: to compute use "nix-hash --type sha256 --flat"
-        fileSize :: Integer,
-        -- ^ file size of compressed nar file
+        fileHash :: Text,
+        -- | file size of compressed nar file
         -- NOTE: du -b
-        narHash :: Text,
-        -- ^ sha256 hash of the decompressed nar file
+        fileSize :: Integer,
+        -- | sha256 hash of the decompressed nar file
         -- NOTE: to compute use "nix-hash --type sha256 --flat --base32"
-        narSize :: Integer,
-        -- ^ file size of decompressed nar file
+        narHash :: Text,
+        -- | file size of decompressed nar file
         -- NOTE: du -b
-        references :: [Text],
-        -- ^ immediate dependencies of the storePath
+        narSize :: Integer,
+        -- | immediate dependencies of the storePath
         -- NOTE: nix-store -q --references
-        deriver :: Text,
-        -- ^ relative store path (to nix store root) of the deriver
+        references :: [Text],
+        -- | relative store path (to nix store root) of the deriver
         -- NOTE: nix-store -q --deriver
+        deriver :: Text,
+        -- | signature of fields: storePath, narHash, narSize, refs
         sig :: Text
-        -- ^ signature of fields: storePath, narHash, narSize, refs
-        }
+      }
   deriving (Generic, Show, FromJSON, ToJSON, ToSchema)
 
 data BinaryCache
@@ -55,41 +54,25 @@
         isPublic :: Bool,
         publicSigningKeys :: [Text],
         githubUsername :: Text
-        }
+      }
   deriving (Show, Generic, FromJSON, ToJSON, ToSchema, NFData)
 
 newtype BinaryCacheError
   = BinaryCacheError
       { error :: Text
-        }
+      }
   deriving (Generic, FromJSON, ToJSON)
 
--- | Hash of nar.xz file
-newtype NarC = NarC Text deriving (Generic, ToSchema, ToParamSchema)
-
-instance FromHttpApiData NarC where
-
-  parseUrlPiece s =
-    if takeEnd 7 s == ".nar.xz"
-      then Right $ NarC (dropEnd 7 s)
-      else Left ""
-
-instance ToHttpApiData NarC where
-
-  toUrlPiece (NarC n) = n <> ".nar.xz"
-
 -- | Store path hash
 newtype NarInfoC = NarInfoC Text deriving (Generic, ToSchema, ToParamSchema)
 
 instance FromHttpApiData NarInfoC where
-
   parseUrlPiece s =
     if takeEnd 8 s == ".narinfo"
       then Right $ NarInfoC (dropEnd 8 s)
       else Left ""
 
 instance ToHttpApiData NarInfoC where
-
   toUrlPiece (NarInfoC n) = n <> ".narinfo"
 
 data User
@@ -100,7 +83,7 @@
         hasOrgsAcccess :: Bool,
         activeSubscription :: SubscriptionType,
         subscriptionAccountId :: Maybe Text
-        }
+      }
   deriving (Generic, FromJSON, ToJSON, ToSchema)
 
 data SubscriptionType = Community | Starter | Basic | Pro
diff --git a/src/Cachix/Types/BinaryCacheAuthenticated.hs b/src/Cachix/Types/BinaryCacheAuthenticated.hs
--- a/src/Cachix/Types/BinaryCacheAuthenticated.hs
+++ b/src/Cachix/Types/BinaryCacheAuthenticated.hs
@@ -1,15 +1,14 @@
 module Cachix.Types.BinaryCacheAuthenticated
-  ( BinaryCacheAuthenticated (..)
-    )
+  ( BinaryCacheAuthenticated (..),
+  )
 where
 
 import Data.Aeson
   ( FromJSON,
-    ToJSON
-    )
+    ToJSON,
+  )
 import Data.Swagger
-import Data.Text (Text)
-import GHC.Generics (Generic)
+import Protolude
 
 -- | Binary Cache response content when user is authenticated
 data BinaryCacheAuthenticated
@@ -19,5 +18,5 @@
         publicSigningKeys :: [Text],
         isPublic :: Bool,
         totalFileSize :: Integer
-        }
+      }
   deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
diff --git a/src/Cachix/Types/BinaryCacheCreate.hs b/src/Cachix/Types/BinaryCacheCreate.hs
--- a/src/Cachix/Types/BinaryCacheCreate.hs
+++ b/src/Cachix/Types/BinaryCacheCreate.hs
@@ -1,15 +1,14 @@
 module Cachix.Types.BinaryCacheCreate
-  ( BinaryCacheCreate (..)
-    )
+  ( BinaryCacheCreate (..),
+  )
 where
 
 import Data.Aeson
   ( FromJSON,
-    ToJSON
-    )
+    ToJSON,
+  )
 import Data.Swagger
-import Data.Text (Text)
-import GHC.Generics (Generic)
+import Protolude
 
 data BinaryCacheCreate
   = BinaryCacheCreate
@@ -17,5 +16,5 @@
         isPublic :: Bool,
         githubOrganization :: Maybe Text,
         githubTeamId :: Maybe Int
-        }
+      }
   deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
diff --git a/src/Cachix/Types/ContentTypes.hs b/src/Cachix/Types/ContentTypes.hs
--- a/src/Cachix/Types/ContentTypes.hs
+++ b/src/Cachix/Types/ContentTypes.hs
@@ -3,15 +3,15 @@
 module Cachix.Types.ContentTypes
   ( XNixNar,
     XNixNarInfo,
-    XNixCacheInfo
-    )
+    XNixCacheInfo,
+  )
 where
 
 import Cachix.Api.Types
-import Data.ByteString (ByteString)
-import Data.ByteString.Lazy (fromStrict, toStrict)
+import qualified Data.ByteString.Lazy as BSL
 import Data.Typeable (Typeable)
 import qualified Network.HTTP.Media as M
+import Protolude
 import Servant.API
 
 data XNixNar deriving (Typeable)
@@ -21,29 +21,22 @@
 data XNixCacheInfo deriving (Typeable)
 
 instance Accept XNixCacheInfo where
-
   contentType _ = "application" M.// "octet-stream"
 
 instance Accept XNixNarInfo where
-
   contentType _ = "text" M.// "x-nix-narinfo"
 
 instance Accept XNixNar where
-
   contentType _ = "application" M.// "x-nix-nar"
 
 instance MimeUnrender XNixCacheInfo NixCacheInfo where
-
   mimeUnrender _ _ = Left "TODO"
 
 instance MimeUnrender XNixNarInfo NarInfo where
-
   mimeUnrender _ _ = Left "TODO"
 
 instance MimeRender XNixNar ByteString where
-
-  mimeRender _ = fromStrict
+  mimeRender _ = BSL.fromStrict
 
 instance MimeUnrender XNixNar ByteString where
-
-  mimeUnrender _ = Right . toStrict
+  mimeUnrender _ = Right . BSL.toStrict
diff --git a/src/Cachix/Types/CreateToken.hs b/src/Cachix/Types/CreateToken.hs
new file mode 100644
--- /dev/null
+++ b/src/Cachix/Types/CreateToken.hs
@@ -0,0 +1,17 @@
+module Cachix.Types.CreateToken
+  ( CreateToken (..),
+  )
+where
+
+import Data.Aeson
+  ( FromJSON,
+    ToJSON,
+  )
+import Data.Swagger
+import Protolude
+
+data CreateToken
+  = CreateToken
+      { description :: Text
+      }
+  deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
diff --git a/src/Cachix/Types/GitHubTeam.hs b/src/Cachix/Types/GitHubTeam.hs
--- a/src/Cachix/Types/GitHubTeam.hs
+++ b/src/Cachix/Types/GitHubTeam.hs
@@ -1,19 +1,18 @@
 module Cachix.Types.GitHubTeam
-  ( GitHubTeam (..)
-    )
+  ( GitHubTeam (..),
+  )
 where
 
 import Data.Aeson
   ( FromJSON,
-    ToJSON
-    )
+    ToJSON,
+  )
 import Data.Swagger
-import Data.Text (Text)
-import GHC.Generics (Generic)
+import Protolude
 
 data GitHubTeam
   = GitHubTeam
       { id :: Int,
         name :: Text
-        }
+      }
   deriving (Generic, FromJSON, ToJSON, ToSchema)
diff --git a/src/Cachix/Types/NarFileName.hs b/src/Cachix/Types/NarFileName.hs
new file mode 100644
--- /dev/null
+++ b/src/Cachix/Types/NarFileName.hs
@@ -0,0 +1,25 @@
+module Cachix.Types.NarFileName
+  ( NarFileName (..),
+  )
+where
+
+import Data.Text (dropEnd, takeEnd)
+import Protolude
+import Servant.API
+
+-- | <hash>.nar.xz file
+data NarFileName
+  = NarFileName
+      { contentHash :: Text,
+        extension :: Text
+      }
+  deriving (Generic)
+
+instance FromHttpApiData NarFileName where
+  parseUrlPiece s =
+    if takeEnd 7 s == ".nar.xz"
+      then Right $ NarFileName (dropEnd 7 s) "xz"
+      else Left "Wrong extension"
+
+instance ToHttpApiData NarFileName where
+  toUrlPiece narfilename = contentHash narfilename <> ".nar." <> extension narfilename
diff --git a/src/Cachix/Types/NarInfoCreate.hs b/src/Cachix/Types/NarInfoCreate.hs
--- a/src/Cachix/Types/NarInfoCreate.hs
+++ b/src/Cachix/Types/NarInfoCreate.hs
@@ -1,26 +1,26 @@
 module Cachix.Types.NarInfoCreate
   ( NarInfoCreate (..),
     NarInfoInvalid,
-    isNarInfoCreateValid
-    )
+    isNarInfoCreateValid,
+  )
 where
 
-import Control.Exception (Exception)
 import Data.Aeson
   ( FromJSON,
-    ToJSON
-    )
+    ToJSON,
+  )
 import Data.Swagger
-import Data.Text (Text)
-import GHC.Generics (Generic)
+import Protolude
 
 -- TODO: get rid of c prefix
 
 -- | Client create type
 data NarInfoCreate
   = NarInfoCreate
-      { cStoreHash :: Text, -- ^ $storePrefix / $storeHash - $storeSuffix
-        cStoreSuffix :: Text, -- ^ $storePrefix / $storeHash - $storeSuffix
+      { -- | \$storePrefix / $storeHash - $storeSuffix
+        cStoreHash :: Text,
+        -- | \$storePrefix / $storeHash - $storeSuffix
+        cStoreSuffix :: Text,
         cNarHash :: Text,
         cNarSize :: Integer,
         cFileHash :: Text,
@@ -28,7 +28,7 @@
         cReferences :: [Text],
         cDeriver :: Text,
         cSig :: Text
-        }
+      }
   deriving (Generic, Show, FromJSON, ToJSON, ToSchema)
 
 data NarInfoInvalid
diff --git a/src/Cachix/Types/Servant.hs b/src/Cachix/Types/Servant.hs
--- a/src/Cachix/Types/Servant.hs
+++ b/src/Cachix/Types/Servant.hs
@@ -6,11 +6,11 @@
 module Cachix.Types.Servant
   ( Get302,
     Post302,
-    Head
-    )
+    Head,
+  )
 where
 
-import Data.Text (Text)
+import Protolude
 import Servant.API
 
 -- Location header as per https://github.com/haskell-servant/servant/issues/117#issuecomment-381398666
diff --git a/src/Cachix/Types/Session.hs b/src/Cachix/Types/Session.hs
--- a/src/Cachix/Types/Session.hs
+++ b/src/Cachix/Types/Session.hs
@@ -1,20 +1,19 @@
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE DeriveGeneric #-}
-
--- | Module for auth session storage
+-- | Auth representations
 module Cachix.Types.Session
   ( Session (..),
-    UserId
-    )
+  )
 where
 
-import Data.Aeson (FromJSON, ToJSON)
-import GHC.Generics (Generic)
--- TODO: move these two into Servant.Auth
-import Servant.Auth.Server (FromJWT, ToJWT)
+import qualified Crypto.JWT as JWT
+import Protolude
+import Servant.Auth.Server (FromJWT (..), ToJWT (..))
 
-type UserId = Integer
+data Session
+  = JWTSession JWT.ClaimsSet
+  deriving (Eq)
 
-newtype Session
-  = Session UserId
-  deriving (Eq, Show, Generic, FromJSON, ToJSON, FromJWT, ToJWT)
+instance ToJWT Session where
+  encodeJWT (JWTSession s) = s
+
+instance FromJWT Session where
+  decodeJWT cs = pure $ JWTSession cs
diff --git a/src/Cachix/Types/SigningKeyCreate.hs b/src/Cachix/Types/SigningKeyCreate.hs
--- a/src/Cachix/Types/SigningKeyCreate.hs
+++ b/src/Cachix/Types/SigningKeyCreate.hs
@@ -1,19 +1,18 @@
 module Cachix.Types.SigningKeyCreate
-  ( SigningKeyCreate (..)
-    )
+  ( SigningKeyCreate (..),
+  )
 where
 
 import Data.Aeson
   ( FromJSON,
-    ToJSON
-    )
+    ToJSON,
+  )
 import Data.Swagger
-import Data.Text (Text)
-import GHC.Generics (Generic)
+import Protolude
 
 -- | Conveys that a signing secret key was created, by sharing the public key.
 newtype SigningKeyCreate
   = SigningKeyCreate
       { publicKey :: Text
-        }
+      }
   deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
diff --git a/src/Cachix/Types/SwaggerOrphans.hs b/src/Cachix/Types/SwaggerOrphans.hs
--- a/src/Cachix/Types/SwaggerOrphans.hs
+++ b/src/Cachix/Types/SwaggerOrphans.hs
@@ -8,12 +8,9 @@
 module Cachix.Types.SwaggerOrphans
   where
 
-import Control.DeepSeq (NFData)
-import Data.Proxy   (Proxy(..))
+import Protolude
 import Data.Conduit (ConduitT)
 import Data.Swagger (ToSchema(..))
-import Servant.API  (NoContent)
-
 
 -- TODO: upstream to servant-conduit
 instance ToSchema i => ToSchema (ConduitT i o m r) where
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -11,4 +11,4 @@
     config =
       defaultConfig
         { configColorMode = ColorAlways
-          }
+        }
