servant-auth's People
Forkers
soenkehahn bts ewestern martyall1 jb55 jasonzoladz drever kelecorix domenkozar iteloo ericnething sordina freckletonj 3noch phadej albertov jamesthompson gkleen grafted-in rikvdkleij mbeidler lumiguide roberth rjregenold danbroooks kakkun61 alasconnect defanor harendra-kumar tomsmalley hamishmack dmjio sopvop karshan xaviershay triggernz adetokunbo mschristiansen dragonfly-science tshinohara alexjg radisson esjmb matbyl sajidanower23 cdepillabout benkolera dredozubov jfischoff ajchapman gusbicalho mattaudesse mrcd acondolu serokell odr tathougies jkaye2012 poscat0x04 jkachmar pwm philderbeast akhesacaro futtetennista kleidukos dnikolovv adithyaov gulinss tchoutri scarf-sh chansuke diamondy4 silkyservant-auth's Issues
Extensible CSRF handling
cookie authentication without csrf
I'd like to protect a route that returns an HTML page with cookie authentication.
Based on the example from the README, I'd want my routes to look something like this:
type Protected
= "name" :> Get '[JSON] String
:<|> "email" :> Get '[JSON] String
:<|> Raw
type Unprotected =
"login"
:> ReqBody '[JSON] Login
:> PostNoContent
'[JSON]
(Headers
'[ Header "Set-Cookie" SetCookie
, Header "Set-Cookie" SetCookie
]
NoContent)
type API = Unprotected :<|> (Auth '[Cookie] User :> Protected)
If I'm using Cookie
authentiation, the problem with this is that the Raw
routes in Protected
will require that the X-XSRF-TOKEN
header is set. If a user is accessing a page in their browser and clicks a link, I don't think that the X-XSRF-TOKEN
will be set. (Maybe it would be possible to do this somehow with Javascript, but I'd rather not have to take that approach.)
It would be nice to have a separate authentication like CookieNoCSRF
that doesn't check the X-XSRF-TOKEN
header. Is there a way to do this currently? Or would it require an additional authentication method? Or maybe there is a better way?
Cookie Auth broken?
Hi!
curl -v --cookie "JWT-Cookie=eyJhbGciOiJIUzI1NiJ9.eyJkYXQiOnsiZW1haWwiOiJhbGlAZW1haWwuY29tIiwibmFtZSI6IkFsaSBCYWJhIn19.U-PyzI3wJgmJA-aiRl_vH6Ij9l0XN3AmmjP_NtNnolk" http://localhost:7249/name
* Trying ::1...
* connect to ::1 port 7249 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 7249 (#0)
> GET /name HTTP/1.1
> Host: localhost:7249
> User-Agent: curl/7.43.0
> Accept: */*
> Cookie: JWT-Cookie=eyJhbGciOiJIUzI1NiJ9.eyJkYXQiOnsiZW1haWwiOiJhbGlAZW1haWwuY29tIiwibmFtZSI6IkFsaSBCYWJhIn19.U-PyzI3wJgmJA-aiRl_vH6Ij9l0XN3AmmjP_NtNnolk
>
< HTTP/1.1 401 Unauthorized
< Transfer-Encoding: chunked
< Date: Sat, 11 Feb 2017 15:11:50 GMT
< Server: Warp/3.2.9
<
* Connection #0 to host localhost left intact
Using the readme tutorial, after successfully logging in.
It works using the same file with the JWT option.
Any idea how to debug this further?
CSRF gets reset too often causing race condition in browser
When CSRF is enabled, servant-auth-server will set the cookie on every response. The following will happen in the browser with concurrent requests:
- Request A is performed by the browser with token=t1
- Request B is constructed in JavaScript with token=t1
- Response A is received by the browser, sets the cookie to token=t2
- Request B gets sent by the browser with t1 in the XSRF header and t2 in the Cookie header
- Request B gets rejected even though it is legitimate
This may be more or less of a problem depending on the JavaScript technology used. The context switching by GHCJS probably makes this even more likely than otherwise, but Angular may also suffer from this race condition.
Fix references to old repo URL
After change to haskell-servant org.
Tests fail when using 0.2.1.0 release
Running 2 test suites...
Test suite doctest: RUNNING...
doctest: InvalidYaml (Just (YamlException "Yaml file not found: package.yaml"))
Test suite doctest: FAIL
Test suite logged to: dist/test/servant-auth-0.2.1.0-doctest.log
Test suite spec: RUNNING...
Test suite spec: PASS
Test suite logged to: dist/test/servant-auth-0.2.1.0-spec.log
1 of 2 test suites (1 of 2 test cases) passed.
We probably need to add package.yaml
to extra-source-files
section of Cabal.
Issue with switching to 0.12's hoistServer
I had previously worked out how to make my stack with with this library, however, I am now attempting to upgrade to servant 0.12 but have the following problem when trying to use hoistServer
.
Given:
toHandler :: AppContext -> AppM a -> Handler a
toHandler ctx r =
(runLogging . runExceptT . flip runReaderT ctx . runAppM) r >>= \case
Left e -> throwError e
Right v -> return v
server :: CookieSettings -> JWTSettings -> AppContext -> Server Routes
server ccf jcf ctx =
let p = Proxy :: Proxy Routes
h = toHandler ctx
r = routes ccf jcf
in hoistServer p h r
I get:
• No instance for (HasContextEntry '[] CookieSettings)
arising from a use of ‘hoistServer’
• In the expression: hoistServer p h r
In the expression:
let
p = Proxy :: Proxy Routes
h = toHandler ctx
r = routes ccf jcf
in hoistServer p h r
In an equation for ‘server’:
server ccf jcf ctx
= let
p = ...
h = toHandler ctx
....
in hoistServer p h r
What am I missing?
Err 405 when using /login (README example)
After building the README example and running it with Cookie
, I'm running:
curl -v -XPOST -H 'Content-Type: application/json' --data '{"username":"...", "password":"..."}' localhost:7249/login
And getting:
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 7249 (#0)
> POST /login HTTP/1.1
> Host: localhost:7249
> User-Agent: curl/7.43.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 40
>
* upload completely sent off: 40 out of 40 bytes
< HTTP/1.1 405 Method Not Allowed
< Transfer-Encoding: chunked
< Date: Mon, 23 Jan 2017 14:01:43 GMT
< Server: Warp/3.2.8
< Content-Type: text/plain
<
* Connection #0 to host localhost left intact
Only GET or HEAD is supported
But the example is using PostNoContent for "/login"
Using:
- servant-auth-server-0.2.1.0
- servant-auth-0.2.1.0
- jose-0.5.0.0
Update to jose 6
Jose 6 is out and is now in LTS. Some changes will be necessary.
JWT Instances for servant-foreign
It would be handy to have instances for HasForeign
from servant-foreign
Something along the lines of this, I'm not sure about the correctness of using Text to represent JWTs, but I believe this is along the right lines. It could probably be generalised a bit too so it's not fixed to exactly '[JWT]
instance forall lang ftype api.
( HasForeign lang ftype api
, HasForeignType lang ftype Text
)
=> HasForeign lang ftype (Auth '[JWT] a :> api) where
type Foreign ftype (Auth '[JWT] a :> api) = Foreign ftype api
foreignFor lang Proxy Proxy subR =
foreignFor lang Proxy (Proxy :: Proxy api) req
where
req = subR{ _reqHeaders = HeaderArg arg : _reqHeaders subR }
arg = Arg
{ _argName = PathSegment "Authorization"
, _argType = typeFor lang (Proxy :: Proxy ftype) (Proxy :: Proxy Text)
}
The documentation for the latest version of this package is missing on Hackage.
The documentation for the latest version of this servant-auth-servant is missing on Hackage. They've been pending on Hackage for some time, this usually indicated that Hackage wasn't able to build the package.
Is it possible for you to manually upload the package using cabal upload --doc
, please?
Thanks!
Authorization versus Authentication
This intentionally overlaps/duplicates #5, since that issue is relatively old and servant-auth
, as well as Servant itself, has changed substantially since then.
Right now it's looking like servant-auth
is going to become the blessed form of authentication handling in Servant, and one of the areas that's really lacking right now is how to handle route authorization through a custom combinator.
I don't really have a great solution in my mind, except that I'd like to have a combinator - or documented process of writing some combinator - that accepts the result of servant-auth
's authentication and can then authorize access to a route based on the information there.
It'd be particularly useful if there was a documented method to use such a combinator inside a custom application transformer stack, as my main motivating example would be decoding the authentication token and using a DB connection in some ReaderT
stack to check the permissions for that user's ID.
Missing exports for checking auth
These should be exported to be able to check auth in raw WAI Applications:
Servant.Auth.Server.Internal.JWT.jwtAuthCheck
Servant.Auth.Server.Internal.Types.AuthCheck(..)
Cookie support in servant-auth-swagger
I'd like to use cookie based auth with toSwagger
but I get this error
• No instance for (Data.Swagger.Internal.ParamSchema.ToParamSchema
SetCookie)
arising from a use of ‘toSwagger’
• In the first argument of ‘(&)’, namely ‘toSwagger api’
In the first argument of ‘(&)’, namely
‘toSwagger api & info . title .~ "Gramm API"’
In the first argument of ‘(&)’, namely
‘toSwagger api & info . title .~ "Gramm API"
& info . version .~ "1.0"’
What is necessary for cookie auth support? If it's not too complicated I'd be glad to take care of it.
Support Origin check for alternative CSRF protection
In single-page-apps it seems checking the Origin
header is a much simpler and easier way of preventing CSRF than using a CSRF-token. I'd like to use that method instead but it seems this library does not directly support it.
The "WWW-Authenticate" header
When Servant.Auth.Server.BasicAuth
is used, Servant.Auth
doesn't
send the WWW-Authenticate
header by itself, leaving it to a user. I
see the wwwAuthenticatedErr
function in
Servant.Auth.Server.Internal.BasicAuth
, but haven't found it being
exported from non-internal modules, and it is confusing overall: is it
intended for use by a user?
AddSetCookies regression for function types
It seems that AddSetCookies
currently (0.2.2.0) doesn't work for function types: if I have a handler like Int -> Handler Int
behind Auth schemes session
, I get an Overlapping instances
error.
For the following program,
#!/usr/bin/env stack
-- stack --resolver lts-7.8 --install-ghc runghc --package servant-0.9.1.1 --package servant-server-0.9.1.1 --package http-api-data-0.3.5 --package servant-auth-0.2.1.0 --package servant-auth-server-0.2.2.0 --package jose-0.5.0.0
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import Network.Wai.Handler.Warp (run)
import Servant
import Servant.Auth.Server
import Servant.Auth.Server.SetCookieOrphan ()
instance ToJWT ()
instance FromJWT ()
type Protected = "int" :> ReqBody '[JSON] Int :> Post '[JSON] Int
type Api auths = (Auth auths () :> Protected)
api = Proxy :: Proxy (Api '[JWT, Cookie])
intHandler :: Int -> Handler Int
intHandler = return
protected :: AuthResult () -> Server Protected
protected (Authenticated user) = intHandler
protected _ = throwAll err401
server :: CookieSettings -> JWTSettings -> Server (Api auths)
server cs jwts = protected
main = do
myKey <- generateKey
let jwtCfg = defaultJWTSettings myKey
cfg = defaultCookieSettings :. jwtCfg :. EmptyContext
run 8000 $ serveWithContext api cfg (server defaultCookieSettings jwtCfg)
I get this compilation error:
asc-bug.hs:34:14: error:
• Overlapping instances for Servant.Auth.Server.Internal.AddSetCookie.AddSetCookies
('Servant.Auth.Server.Internal.AddSetCookie.S
('Servant.Auth.Server.Internal.AddSetCookie.S
'Servant.Auth.Server.Internal.AddSetCookie.Z))
(Int -> Control.Monad.Trans.Except.ExceptT ServantErr IO Int)
(Int
-> Control.Monad.Trans.Except.ExceptT
ServantErr
IO
(Headers
'[Header "Set-Cookie" SetCookie,
Header "Set-Cookie" SetCookie]
Int))
arising from a use of ‘serveWithContext’
Matching instances:
instance [overlap ok] Servant.Auth.Server.Internal.AddSetCookie.AddSetCookies
n oldb newb =>
Servant.Auth.Server.Internal.AddSetCookie.AddSetCookies
n (a -> oldb) (a -> newb)
-- Defined in ‘Servant.Auth.Server.Internal.AddSetCookie’
...plus one instance involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the second argument of ‘($)’, namely
‘serveWithContext api cfg (server defaultCookieSettings jwtCfg)’
In a stmt of a 'do' block:
run 8000
$ serveWithContext api cfg (server defaultCookieSettings jwtCfg)
In the expression:
do { myKey <- generateKey;
let jwtCfg = defaultJWTSettings myKey
cfg = defaultCookieSettings :. jwtCfg :. EmptyContext;
run 8000
$ serveWithContext api cfg (server defaultCookieSettings jwtCfg) }
When I switch from servant-auth-server 0.2.2.0 back to servant-auth-server 0.2.1.0, the code compiles successfully.
Better JWT verification failure information and add "dat" documentation
First off, thanks for making this. I have this successfully implemented and it does exactly what I need. I know this library is new, but want to give some feedback and see if I can help out. I'm fairly new to Haskell+Servant so I apologize if any of these are not issues with more knowledge.
One issue I had was dealing with AuthResult
failures while trying to get everything to flow. What was difficult is when I received the AuthResult
I had no insight into why it failed. For a long time I thought it was JWT configuration issues until I started pulling code out of the lib to see what was really happening. This part in particular:
Once I realized it was actually verifying correctly and it was just JWT decode issues on my type, it was easy to get it going.
Another issue was not realizing that it was looking in unregistered claims for the keyword "dat". I'm using Auth0 to generate tokens and did not realize was trying to decode from there specifically. I assumed it'd be the entire payload.
Once again, thanks for putting this out there. I'm definitely open to help address these if you can point me in the right direction!
Support servant-auth-0.3.*
I'm trying to build servant-auth-server
via nixpkgs.
$ nix-build -A haskellPackages.servant-auth-server
...
cabal: Encountered missing dependencies:
jose ==0.5.*, servant-auth ==0.2.*
The build environment has jose-0.6.0.3
and servant-auth-0.3.0.0
. I see there's already a PR for upgrading to jose-0.6.
It would be great if servant-auth-server
could support servant-auth-0.3.*
.
README's checkCred won't work as advertised
Since the cookie that is set is the unauthenticated cookie rather than the new one.
CSRF tokens should not be required for stateless HTTP methods
Hi there,
Thank you for this library!
I've noticed that CSRF tokens seem to be required for GET
, HEAD
, OPTIONS
, and TRACE
requests, but these methods should never change any state, so they are safe to be performed without a token.
See:
- https://docs.spring.io/spring-security/site/docs/3.2.7.RELEASE/apidocs/org/springframework/security/web/csrf/CsrfFilter.html
- https://elithrar.github.io/article/preventing-csrf-attacks-in-go/
- https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/
I'm submitting another issue shortly, and I am going to try to help out with these issues.
`ThrowAll` and `EmptyServer`
I can't seem to use throwAll
with an API type containing an EmptyServer
anywhere in it. I have a MonadError ServantErr m
instance for my monad stack (below) and throwAll
works for other types of routes.
Here's a minimal reproduction:
newtype AppT m a
= AppT
{ runApp :: ReaderT Environment (ExceptT ServantErr m) a
} deriving ( Functor, Applicative, Monad, MonadReader Environment,
MonadError ServantErr, MonadIO)
data ApiUser = ApiUser
{ UserId :: Int64
} deriving (Eq, Show, Generic, ToJSON, FromJSON)
instance ToJWT ApiUser
instance FromJWT ApiUser
type MyAPI auths = Auth auths ApiUser :> EmptyAPI
myPrivateServer :: MonadIO m => AuthResult ApiUser -> ServerT EmptyAPI (AppT m)
myPrivateServer (Authenticated _user) = emptyServer
myPrivateServer _ = throwAll err401
This unfortunately gives me the following error:
Could not deduce (Control.Monad.Error.Class.MonadError
ServantErr (Tagged (AppT m)))
arising from a use of ‘throwAll’
from the context: MonadIO m
bound by the type signature for:
myPrivateServer :: MonadIO m =>
AuthResult ApiUser -> ServerT EmptyAPI (AppT m)
Document how this package relates to Servant.API.Experimental.Auth and servant's BasicAuth
It could be easier to evaluate this package if some pros and cons were described in the README.
Make AddSetCookieApi open
So that people can define their own end combinators.
Probably should also define a new instance for Stream
.
HasClient instances seem not to be there?
Perhaps I've done something silly, but with this test code:
fullAPI :: Proxy (API '[Cookie])
fullAPI = Proxy
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module FullAPISpec where
import Test.Hspec
import Web.FullAPI
import Servant.Auth.Server (generateKey)
import Control.Concurrent(forkIO, killThread)
import Control.Exception(bracket)
import Network.Wai.Handler.Warp (run)
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
import Servant.Common.BaseUrl(BaseUrl(..))
import Servant.Client(client)
import Servant.Server(serveWithContext)
import Servant.Auth.Client()
withServer p = bracket (startServer p) killServer
killServer = killThread . fst
startServer p = do
(cfg,server) <- mkServer <$> generateKey
handle <- forkIO $ run p $ logStdoutDev $ serveWithContext fullAPI cfg server
return (handle, client fullAPI) -- (BaseUrl Http "localhost" p))
spec :: Spec
spec =
around (withServer 8888) $
describe "full interaction" $ do
it "should do things" $ \(cfg,server) -> do
pending
I get this:
/home/mark/startup/emails/thirstyrando/test/FullAPISpec.hs:25:19: error:
• No instance for Servant.Auth.Client.Internal.JWTAuthNotEnabled
arising from a use of ‘client’
• In the expression: client fullAPI
In the first argument of ‘return’, namely
‘(handle, client fullAPI)’
In a stmt of a 'do' block: return (handle, client fullAPI)
I might be doing something silly - have you got an example of using servant-client with a protected API?
Orphans for SetCookie break derived clients
Since the ToHttpApiData
instances for SetCookie
are only available as orphans in servant-auth-server
, clients that use the same API type will not be able to derive client functions because these instances will be missing. These instances need to be pulled out into a different library or included in servant-auth
itself.
(Cookie) No instance for Servant.Foreign.Internal.HasForeign
JavaScript code generation fails with the following error message:
/Users/kseo/KodeBoxProjects/kodebox/kodebox-server/jsgen/Main.hs: 27, 15
• No instance for (servant-foreign-0.9.1.1:Servant.Foreign.Internal.HasForeign
NoTypes
Servant.API.ContentTypes.NoContent
(servant-auth-0.2.1.0:Servant.Auth.Auth '[Cookie] Session
Servant.API.Sub.:> Kodebox.Server.Api.Protected))
arising from a use of ‘writeJSForAPI’
• In the expression:
writeJSForAPI
restApi vanillaJS (joinPath [outputDir, "Kodebox.js"])
In an equation for ‘writeJSCode’:
writeJSCode
= writeJSForAPI
restApi vanillaJS (joinPath [outputDir, "Kodebox.js"])
Is ToJWT/FromJWT a requirement for a custom IsAuth?
I'm writing a custom Auth strategy for decrypting a Rails session cookie. I've got the following POC code working (actual decryption code, yet to be plugged in). This problem is:
- This code compiles
- And, the handler code with
AuthResult RailsCookie.UserId
in it's signature compiles, - But, the actual
serveWithContext
fails with the following error:
194 25 error error:
• No instance for (Auth.ToJWT UserId)
arising from a use of ‘serveWithContext’
• In the expression:
serveWithContext api (cookieSettings :. EmptyContext) server
In an equation for ‘serverApplication’:
serverApplication
= serveWithContext api (cookieSettings :. EmptyContext) server
In the expression:
let
cookieSettings = RailsCookieSettings {cookieName = "myAuth"}
handlers = (PaxManifestEp.server :<|> TestEp.server)
server = enter (NT appmToServantM) handlers
....
in (serverApplication req respHandler) (intero)
Do I need to define ToJWT and FromJWT instances even though I have nothing to do with JWT?
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Servant.Auth.Server.Internal.RailsCookie
(
RailsCookie
, RailsCookieSettings(..)
, UserId
) where
import Servant.Auth.Server
import Data.Aeson
import GHC.Generics
import Servant.Auth.Server.Internal.Class
import Servant.Auth.Server.Internal.Types
import Control.Monad.Reader
import Web.Cookie
import Network.Wai (requestHeaders)
import Data.ByteString
import Data.ByteString.Char8 as C8
data RailsCookie
data RailsCookieSettings = RailsCookieSettings
{
cookieName :: ByteString
} deriving (Show, Eq)
newtype UserId = UserId Integer deriving (Show, Eq, Ord, Generic)
instance IsAuth RailsCookie UserId where
type AuthArgs RailsCookie = '[RailsCookieSettings]
runAuth _ _ = railsCookieCheck
railsCookieCheck :: RailsCookieSettings -> AuthCheck UserId
railsCookieCheck cookieSettings = do
request <- ask -- AuthCheck is a Reader with Request as its environment
encryptedCookie <- maybe mempty return (mEncryptedCookie request)
return $ UserId $ read $ C8.unpack encryptedCookie
where
mEncryptedCookie request = lookup "Cookie" (requestHeaders request)
>>= (return.parseCookies)
>>= lookup (cookieName cookieSettings)
Support servant-server 0.10
The latest version of servant-auth-server
at the time of writing has a >=0.9.1 && <0.10
constraint on servant-server
. Would be nice if the latest version of servant-server
(0.10) was supported.
functions for reading and writing keys
first off, kudos! it was surprisingly easy to add auth to my app with this.
Now that i want to push it into prod, i need some way to not recreate the key every time i restart the process. is there an approved way to do that? should i consider Jose.Crypto as part of the public api?
make X-XSRF-TOKEN header for GET requests optional based on settings
The cookie authentication check seems to require the X-XSRF-TOKEN header irrespective of the request type. Refer to this code.
As far as I understand it is not necessary for GET requests to check for CSRF protection as it is not a state modifying operation. However, one can argue that someone can use GET for state modification. The current scheme is very restrictive and cannot work for GET requests from browsers without triggering it from javascript, we should make the GET request protection optional so that we can disable it if we want to.
The documentation for the latest version of this package is missing on Hackage.
The documentation for the latest version of this package is missing on Hackage. It's possible that Hackage wasn't able to build the package.
Is it possible for you to manually upload the package using cabal upload --doc
, please? Note that this requires cabal-install >= 1.24
Thanks!
Compile error with GHC 7.8
Fwiw, the cabal file specifies base >= 4.7
Configuring component lib from servant-auth-client-0.2.1.0
Preprocessing library servant-auth-client-0.2.1.0...
[1 of 2] Compiling Servant.Auth.Client.Internal ( src/Servant/Auth/Client/Internal.hs, /tmp/matrix-worker/1480349576/dist-newstyle/build/x86_64-linux/ghc-7.8.4/servant-auth-client-0.2.1.0/build/Servant/Auth/Client/Internal.o )
src/Servant/Auth/Client/Internal.hs:46:1:
No parameters for class ‘JWTAuthNotEnabled’
(Use NullaryTypeClasses to allow no-parameter classes)
In the class declaration for ‘JWTAuthNotEnabled’
also:
Configuring component lib from servant-auth-docs-0.2.1.0
Preprocessing library servant-auth-docs-0.2.1.0...
[1 of 1] Compiling Servant.Auth.Docs ( src/Servant/Auth/Docs.hs, /tmp/matrix-worker/1480348605/dist-newstyle/build/x86_64-linux/ghc-7.8.4/servant-auth-docs-0.2.1.0/build/Servant/Auth/Docs.o )
src/Servant/Auth/Docs.hs:61:41:
Not in scope: ‘<$>’
Perhaps you meant ‘<>’ (imported from Data.Monoid)
src/Servant/Auth/Docs.hs:63:41:
Not in scope: ‘<$>’
Perhaps you meant ‘<>’ (imported from Data.Monoid)
However, I've also noticed a more fundamental problem with servant-auth-server
:
Configuring component exe:readme from servant-auth-server-0.2.1.0
Preprocessing executable 'readme' for servant-auth-server-0.2.1.0...
ghc: could not execute: markdown-unlit
The package appears to build-depends
on markdown-unlit
, however, build-depends
only requests the library component of a package, and not its executables. It was a bug in previous versions of cabal
, and future versions of cabal don't support this anymore. There will be a tool-depends: ...
for specifying executable dependencies, but it's not available yet.
No way to get a CSRF token when using creds-based auth and cookies
CSRF cookies seem to be set in response to requests authenticated with a Bearer
token, but not in response to those authenticated with a cookie the user logging in with credentials.
It seems like this functionality should be swapped:
- Responses to
Bearer
-authenticated (API) requests should not set a CSRF cookie - Responses to
Cookie-authenticatedthe user logging in with creds (browser) requests should set a CSRF cookie
See also #10
Make auth issue debugging easier - attach reason to Indefinite
Currently it is hard to debug without changing the code of the package. For example, I ran into a cookie authentication issue and it was failing because X-XSRF-TOKEN was not present. The cookieAuthCheck
code just calls the fail
method if loopup fails which is not easy to see in the code ultimately it returns just Indefinite
for all these failure cases. It would be of great help if we can attach failure reason with the Indefinite
constructor.
CI job for GHC-7.8.4
... or if it's unsupported configuration, correct the bounds.
GHC-8.2 support
blocked on frasertweedale/hs-jose#51
Export SameSite et all
Right now SameSite
and its constructors are in Internal.ConfigTypes
even though it represents a core part of the API.
Protecting Raw routes.
I have a protected api type that defines a Raw
route for websocket handling, like so:
type PrivApi =
"foo" :> ReqBody '[JSON] Bar :> PostCreated '[JSON] Bar
:<|> "foo" :> "stream" :> Raw
type Api =
"login" :> ReqBody '[JSON] Creds :> Post '[JSON] Token
:<|> Auth '[JWT] Session :> PrivApi
mkPrivApi :: AuthResult Session -> Server PrivApi
mkPrivApi (Authenticated s) = ...
mkPrivApi _ = throwAll err401
The problem here is that throwAll
does not work in this case:
• Couldn't match type ‘GHC.IO.Exception.IOException’
with ‘ServantErr’
arising from a functional dependency between:
constraint ‘MonadError ServantErr IO’
arising from a use of ‘throwAll’
instance ‘MonadError GHC.IO.Exception.IOException IO’
at <no location info>
• In the expression: throwAll err401
In an equation for ‘mkPrivApi’: mkPrivApi _ = throwAll err401
I tried to circumvent this by pulling the Raw
route out of my PrivApi
type (so that I can use throwAll
) and putting it as an individually protected route in Api
. But this lead to following error:
• No instance for (HasServer
(Servant.Auth.Server.Internal.AddSetCookie.AddSetCookieApi Raw)
'[JWTSettings, CookieSettings])
arising from a use of ‘serveWithContext’
Is there any way I can protect Raw
routes like these?
servant-auth-server 0.2.2.0 seems to break PVP
I have a project that compiled fine with servant-auth-server-0.2.1.0
, but after the update to 0.2.2.0
started failing to build with the following errors:
backend/src/srv/Main.hs:121:25: error:
• No instance for (ToHttpApiData SetCookie)
arising from a use of ‘serveWithContext’
[...]
backend/test/Main.hs:99:13: error:
• No instance for (ToHttpApiData
cookie-0.4.2.1:Web.Cookie.SetCookie)
arising from a use of ‘serveWithContext’
[...]
This can be fixed by adding a Servant.Auth.Server.SetCookieOrphan ()
import to import the required instances (before that I only needed to import Servant.Auth.Server
).
I suggest blacklisting 0.2.2.0
by adding a base < 0
dependency and releasing a fixed version 0.2.3.0
that exports the necessary instances from the same modules 0.2.1.0
did, or just bumping the package version to 0.3.0.0
.
Suggestions for API changes and the addition of an Authorize combinator
Hey, moving the discussion from haskell-servant/servant#799 here. I had a few ideas for changes to the servant-auth API with the goal of separating the concerns of authentication, authorization, and the handler. The notable changes being:
- New
Authorize
combinator which ensures an authenticated user is authorized to access a route- The handler for an
Authorize
d route does not deal with the authentication and/or authorization failures that can happen
- The handler for an
- Existing
Auth
combinator becomesAuthenticate
with some small changes- Handler no longer takes
AuthResult user
, instead the Handler is enhanced withmaybeAuthUser :: Handler (Maybe User)
which can be used if desired
- Handler no longer takes
- The
AuthorizeHandler
(name tbd) typeclass which centralizes the logic for the authorization check (:: user -> AuthorizationState user
), what to do for an authorized route when either: a) authentication has not been performed, b) the user is unauthorized.
A short example of a route/handler before and after:
Current API:
type API auths
= (Auth auths User :> Protected)
:<|> ...
type Protected
= "name" :> Get '[JSON] String
:<|> "email" :> Get '[JSON] String
protected :: AuthResult User -> Server Protected
protected (Authenticated user) =
if username user == "admin"
then return (name user) :<|> return (email user)
else throwAll err401
protected _ = throwAll err401
Proposed API:
data IsAdmin
type API auths
= (Authenticate auths User :> Authorize IsAdmin User :> Protected)
:<|> ...
type Protected
= "name" :> Get '[JSON] String
:<|> "email" :> Get '[JSON] String
instance AuthorizeHandler (IsAdmin User) where
whenAuthenticationRequired _ = redirect "login"
whenUnauthorized _ = throwAll err401
authorize _ user =
if username user == "admin"
then return (Authorized user)
else return (Unauthorized "Not admin")
protected :: User -> Server Protected
protected user = return (name user) :<|> return (email user)
I have a doc where I have most of the details (I thought it would be easier to collect thoughts there than in an issue). Feel free to leave comments there or here, it's still and early draft and would appreciate any feedback :)
support encrypted sessions
I'm working on a so far relatively simple application that stores some sensitive data in an encrypted cookie using servant's experimental general authentication. I'd love to switch to servant-auth as Servant's new default, but am missing the functionality to encrypt session data.
One approach might be to encrypt session payloads for cookies with a HttpOnly
flag by default. If the cookie is not meant to be inspected by client side code its content might as well be encrypted to hide it from malicious browser extensions and other potential attackers as well. Such an approach would not entail any loss of functionality as far as I can see, while eliminating a potential error on the side of the library user.
I'm looking forward on others' thoughts on this.
Question about login response
Looking to the example code in the readme, I wonder if it's possible to not respond with token in cookie but to return a JSON object in the repsonse body which contains the token?
When I change:
let jwtCfg = defaultJWTSettings myKey
cfg = defaultCookieSettings :. jwtCfg :. EmptyContext
--- Here we actually make concrete
api = Proxy :: Proxy (API '[JWT])
to
let jwtCfg = defaultJWTSettings myKey
cfg = jwtCfg :. EmptyContext
--- Here we actually make concrete
api = Proxy :: Proxy (API '[JWT])
I get this error:
No instance for (HasContextEntry '[] CookieSettings) arising from a use of ‘serveWithContext’
Syntax highlighting in README
I was going to submit a PR to turn on syntax highlighting for the examples in the readme, but it looks like the examples are already marked up for highlighting, just not using github flavoured markdown. Briefly looking online I couldn't find anywhere that this readme was rendered other than here (hackage points users here for viewing the readme).
Is this a throwback to when this readme would be displayed elsewhere, and it can just be updated to use GFM now?
support writing custom combinators for authorization
The given Auth
combinator takes care of authentication. It would be nice if servant-auth
(or servant
) allowed to easily write a custom combinator MyAuth
that used servant-auth-server
for authentication, but then also took care of authorization, where
Server (MyAuth :> api) ~ MyUser -> Server api
The HasServer
instance would yield 401
s for missing or invalid authentication and 403
for insufficient privileges.
Prepare to be official
servant-auth
is becoming the official auth mechanism for servant
. Before that can happen, we should
ThrowAll + ServerT
Given an existing stack I've been hacking on without servant-auth
:
newtype AppM a
= AppM { runAppM :: ReaderT AppContext (LoggingT (WithSeverity Doc) IO) a }
deriving ( Functor, Applicative, Monad
, MonadIO, MonadThrow
, MonadReader AppContext, MonadLog (WithSeverity Doc))
And some sub-set of my API where I try to include servant-auth
:
type ClientApiProtected =
AssocTerm :> AssociationApi
:<|> AuthTerm :> AuthApi
:<|> ManagedAuthTerm :> ManagedAuthApi
:<|> PermissionTerm :> PermissionApi
:<|> ServiceTerm :> ServiceApi
type ClientApiUnprotected = UserTerm :> UserApi
type ClientApi =
(Auth '[JWT] Session :> ClientApiProtected)
:<|> ClientApiUnprotected
clientApiProtectedServer
:: AuthResult Session -> ServerT ClientApiProtected AppM
clientApiProtectedServer (Authenticated _) =
associationApiServer
:<|> authApiServer
:<|> managedAuthApiServer
:<|> permissionApiServer
:<|> serviceApiServer
clientApiProtectedServer _ = throwAll err401 -- Gah!
clientApiUnprotectedServer
:: CookieSettings -> JWTSettings -> ServerT ClientApiUnprotected AppM
clientApiUnprotectedServer cs jwts = userApiServer
clientApiServer :: CookieSettings -> JWTSettings -> ServerT ClientApi AppM
clientApiServer cs jwts =
clientApiProtectedServer
:<|> clientApiUnprotectedServer cs jwts
I end up with the error:
• No instance for (Control.Monad.Error.Class.MonadError
ServantErr AppM)
arising from a use of ‘throwAll’
• In the expression: throwAll err401
In an equation for ‘clientApiProtectedServer’:
clientApiProtectedServer _ = throwAll err401
What am I missing here? Attempting to add MonadError ServantErr
instances to my AppM
leads me down other rabbit holes, although maybe I am simply doing it wrong.
Getting started example
Hi, I am new to servant and, implicitly, servant-auth. I managed to get the code running in my local instance. However, I am still not clear on how to use the code to protect resources. Would it be possible to provide a more complete example - having user creating accounts or token + defining protected/unprotected endpoints? I do see in the current example code calling
localhost:7249/name -v
However, I still do not see where that is defined, i.e. Thanks for your help.
No instance of `ToHttpApiData` for `ByteString`
I get
src/Servant/Auth/Server/Internal/AddSetCookie.hs:40:27: error:
• Could not deduce (ToHttpApiData BS.ByteString)
arising from a use of ‘addSetCookie’
from the context: Functor m
bound by the instance declaration
at src/Servant/Auth/Server/Internal/AddSetCookie.hs:(38,3)-(39,78)
• In the first argument of ‘(<$>)’, namely ‘addSetCookie cookie’
In the expression: addSetCookie cookie <$> v
In an equation for ‘addSetCookie’:
addSetCookie cookie v = addSetCookie cookie <$> v
cabal: Leaving directory '/tmp/cabal-tmp-23420/servant-auth-server-0.2.0.0'
cabal: Error: some packages failed to install:
servant-auth-server-0.2.0.0-GXwN6DuRKCC9tAHlBkHFuA failed during the building
phase. The exception was:
ExitFailure 1
Looking at the definition of ToHttpApiData
, I am unable to find an instance for ByteString
(not in version 0.3.3 either).
I have compiled against both versions 0.3.2 and 0.3.3, resulting in the same error.
Finally,
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.0.1.20160919
Contents of CSRF tokens not being checked?
Is it intentional that the contents of the CSRF token seem to not be checked for any cryptographic properties, but only that the two values (in the header, and in the cookie) match? maybe per https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet#Protecting_REST_Services:_Use_of_Custom_Request_Headers?
This request succeeds for any token value:
curl -v -H "X-XSRF-TOKEN: foo" -H "Cookie: session=session_goes_here; XSRF-TOKEN=foo" -H "Accept: application/vnd.api+json" "http://localhost:3000/check"
If this intentional and if this suffices to protect against CSRF, maybe we shouldn't bother with #27 or even CSRF tokens at all? and instead just require browsers to set the header X-Requested-With: XMLHttpRequest
as suggested in the owasp link above.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.