Open alexjg opened 6 years ago
I have been suspecting this for a while as well but haven't really taken the time to look closer and try and write my own auth scheme. I think we would not mind exposing more things, so feel free to make a PR, unless @domenkozar or @phadej disagree (unlikely though, we all want the servant libraries to be extensible, and anything standing in the way of that needs to be taken care of).
@alexjg I think that no one has done that yet, so bits may be missing in the public api. If you come up with a list of what needs exporting, or even better a PR, I see no reason to merge that.
Great, I'll have a crack at implementing something and pop in an MR with the required changes in a bit.
So I've just got an auth scheme up and running. The only missing export was the IsAuth
class. However, there appear to be some hard coded requirements on the context for the HasServer
instance for Auth
. Namely this piece of code:
instance ( n ~ 'S ('S 'Z)
, HasServer (AddSetCookiesApi n api) ctxs, AreAuths auths ctxs v
, HasServer api ctxs -- this constraint is needed to implement hoistServer
, AddSetCookies n (ServerT api Handler) (ServerT (AddSetCookiesApi n api) Handler)
, ToJWT v
, HasContextEntry ctxs CookieSettings
, HasContextEntry ctxs JWTSettings
) => HasServer (Auth auths v :> api) ctxs where
type ServerT (Auth auths v :> api) m = AuthResult v -> ServerT api m
This meant I had to add a ToJWT
instance for my user type and the cookie and JWT settings to my context. Is there any reason they're hardcoded in here or could they be removed easily?
In case it's of interest the scheme I'm trying to implement is token authentication but not JWT, just tokens stored in a DB.
FWIW, I have done something similar in my application by hijacking the machinery for BasicAuth. BasicAuth
already has a type family for specifying your own config for a given type. I made my BasicAuthCfg
type instance a custom function which looks in the db for a given token. I just store the token in the password field of the BasicAuth
header and look it up in the db as necessary.
data ApiUserWithToken = ApiUserWithToken
{ apiUser :: ApiUser
, tokenId :: Int64
} deriving (Eq, Show, Generic, ToJSON, FromJSON)
instance ToJWT ApiUserWithToken
instance FromJWT ApiUserWithToken
type instance BasicAuthCfg = BasicAuthData -> IO (AuthResult ApiUserWithToken)
instance FromBasicAuthData ApiUserWithToken where
fromBasicAuthData authData checkBasicAuthFunction = checkBasicAuthFunction authData
If you can have your client use this "custom" basic auth this may be an option for you too.
@alexjg Yes, this is indeed a bit of code we need to change. We don't want to enforce any auth scheme and we therefore don't want to be paying for what we don't use. So again, you should feel free to change whatever is needed to make your auth scheme work well, and we can see in the PR whether we can get away with less changes (I suspect not, as I had spotted some of those issues already and was suspecting there was 2 or 3 places that needed changing).
I submitted a PR as discussed https://github.com/haskell-servant/servant-auth/pull/120
Anyone able to take a look at it?
Nice! I'll try to take a look later today.
Hello everyone! Could someone help me to clarify the status of this issue? Is it possible now to add custom auth schemes to servant
using servant-auth
? I'm working on servant-hmac-auth
library which provides HMAC authentication. But it currently uses old experimental approach for auth:
As far as I can see, this approach is going to be deprecated:
Would be really nice to see some tutorial on how to write custom auth schemes using servant-auth
library 👍
I've had a brief read through the source code and it looks like it should be straightforward to implement a new authorization scheme but the classes I would need to implement aren't exposed as part of the public API (for example the
IsAuth
class). Is this library intended to be extensible in this way or should I just use Servant generalized auth?In case it's of interest the scheme I'm trying to implement is token authentication but not JWT, just tokens stored in a DB.