Skip to content
This repository has been archived by the owner on Oct 29, 2021. It is now read-only.

Is ToJWT/FromJWT a requirement for a custom IsAuth? #40

Closed
saurabhnanda opened this issue Apr 22, 2017 · 4 comments
Closed

Is ToJWT/FromJWT a requirement for a custom IsAuth? #40

saurabhnanda opened this issue Apr 22, 2017 · 4 comments

Comments

@saurabhnanda
Copy link

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)
@saurabhnanda
Copy link
Author

saurabhnanda commented Apr 22, 2017

An aside: Some more documentation around what's going on with runAuth would be appreciate. I have blindly copied & modified the cookieAuthCheck code, without really understanding what's going on with the type signatures!

@jkarni
Copy link
Member

jkarni commented Aug 21, 2017

The reason JWT instances are required is that we use them to generate cookies, and unfortunately we can't have a class constraint be conditional on the configuration data (i.e., whether or not to in fact use cookies). Would just documenting this be helpful?

@domenkozar
Copy link
Collaborator

Closing as duplicate of #119

@ilyakooo0
Copy link

Would it not be possible to move the ToJWT instance to be a constraint of the IsAuth instances where it might actually be used instead of imposing it on all IsAuth instances?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants