haskell-servant / servant

Servat is a Haskell DSL for describing, serving, querying, mocking, documenting web applications and more!
https://docs.servant.dev/
1.82k stars 412 forks source link

Beginner concerns when using the servant-auth-server package #1616

Open qwbarch opened 2 years ago

qwbarch commented 2 years ago

I'm looking for a simple way of handling authentication using servant like this:

  1. User submits credentials to login
  2. User now has access to protected endpoints

The two ways of achieving this as far as I'm aware of is:

  1. Use session ids and store the session data server-sided
  2. Use JWTs to store the user's data client-sided

Now when it comes to the servant ecosystem, it appears there's no simple built-in solution for managing server-sided session. This would be my preference, as my current requirements is to only have one instance of our backend server. JWTs make sense in micro-services since it's stateless, but it seems way too over-kill for our use-case.

I'm not going to roll out own authentication though since I'm not a security expert. I decided to look into servant-auth-server and played around with it.

Here are things I'm concerned about:

Of course the simple solution to the former is to set an expiry date myself. The issue with this now is that if I set the JWT's expiry date to be short-lived (e.g. 15 minutes), users on my website will be forced to login again after 15 minutes.
Even if the cookie extends its expiration, the JWT is expired. If I leave the JWT to be long-lived, then I'm back to square 1.

If I were to add a refresh token endpoint, the Auth combinator seems like it'd have conflicts (in theory), due to it sending that JWT-Cookie by itself every time you send a request to a protected endpoint.

What should I do in my situation? I'd appreciate any feedback, as I don't want to have any potential security issues from misunderstanding how to use this library. Thanks in advance!

and-pete commented 2 years ago

servant-auth-server handles the lifecycle of the JWT through the cookie's expiry date.

Hmm, I guess if you're talking about the default settings of not having an expiry set at all, then sure.

For future readers, this is by deferring it to the user's browser to make that judgement about when to throw away those cookies (...if it's even a browser-based webapp, that is).

The cookies received by the servant-auth-server with client requests aren't expiry-checked at all. We couldn't trust that info even if it was attached to the cookie. Following from that, anyone who has a JWT from one of the Set-Cookie-s does not need to also know anything about what the original Max-Age or Expires attributes were on the Set-Cookie that contained the JWT in order to be able to use the JWT.

It's only the setting of the "exp" claim in the JWT itself that we could potentially use and check on the server end in order to have any confidence that the token we're issuing isn't going to be out there and used forever (or until key resets/etc.).

ProofOfKeags commented 1 year ago

I think requiring the use of JWT's for a server side session store makes this package unapproachable. There should be an option to just use Cookies.