I am using obelisk with servant and servant-snap. I implemented a custom authentication scheme and testing it I encountered a weird error:
A web handler threw an exception. Details: no value
This means: Accessing a backend route (handled by snap), there was an HTTP 500 status code and the error message is quite generic. As far as I understand, snap tries to tell me that there was an unhandled IO exception in the handler. (which I can confirm, because I can catch this IO exception)
Specifically “no value” implies that I am running evalSnap on a snap handler (in my case: authHandler :: Snap UserInfo) that at some point calls finishWith :: Response -> Snap a, which is non-sensical. Only that I never explicitly call finishWith. So this can’t be it.
I then basically sprinkled my code with putStrLn $ "Hi, there!" <> -- ... to figure out what line causes the problem. And I could narrow down the offender to this piece of code:
verifyCompactJWT
:: forall m. (MonadIO m, MonadError JWTError m, MonadBaseControl IO m) => JWK -> CompactJWT -> UTCTime -> m Text
verifyCompactJWT jwk (CompactJWT str) now = do
liftIO $ putStrLn "In verifyCompactJWT"
jwt <- decodeCompact $ BL.fromStrict $ Text.encodeUtf8 str
liftIO $ putStrLn $ "In verifyCompactJWT: jwt: " <> Text.take 16 (Text.pack (show jwt))
let config = defaultJWTValidationSettings (== audience)
claims <- fromJust <$> handle handler (Just <$> verifyClaimsAt config jwk now jwt)
liftIO $ putStrLn $ "In verifyCompactJWT: claims: " <> Text.pack (show claims)
case claims ^. claimSub ^? _Just . string of
Nothing -> do
throwError $ JWTClaimsSetDecodeError "no subject in claims"
Just s -> do
liftIO $ putStrLn $ "verifyCompactJWT: sub: " <> s
pure s
where
handler :: SomeException -> m (Maybe ClaimsSet)
handler e = do
liftIO $ putStrLn $ "Caught exception in verifyCompactJWT: " <> Text.pack (show e)
pure Nothing
verifyCompactJWT is a function called by my handler and this is the output I get:
In verifyCompactJWT
In verifyCompactJWT: jwt: JWS Base64Octets
[23/Jun/2022:15:13:23 -0500] During processing of request from 127.0.0.1:56048
request:
"GET /api/user/app/get HTTP/1.1\naccept-language: en-US,en;q=0.9\nreferer: http://localhost:8000/\nsec-fetch-dest: empty\nsec-fetch-mode: cors\nsec-fetch-site: same-origin\naccept: */*\nsec-ch-ua-platform: \"Linux\"\nx-alias: rubenmoor\nuser-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36\nsec-ch-ua-mobile: ?0\nauthorization: Bearer eyJhbGciOiJFUzM4NCJ9.eyJzdWIiOiJydWJlbm1vb3IiLCJleHAiOjEuNjU1OTQzNjM4NTY0Mzg1Mjc5ZTksImlhdCI6MS42NTU5NDM2MDg1NjQzODUyNzllOSwiYXVkIjoiaHR0cHM6Ly9wYWxhbnR5cGUuY29tIn0.td1jCKoE5QSciU2gUde3FqFrCljSCQzJUwTS09EvfA9K0YY6YZrlfxZakcwCTPLo7c8jI3c5xI32maQok5lQUp50WUcxXz_k1NNeeDmuQfPq0P34HmEJBmcH7S-Dog8G\nsec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"102\", \"Google Chrome\";v=\"102\"\nconnection: keep-alive\nhost: localhost:8000\nx-real-ip: 127.0.0.1\naccept-encoding: gzip\n\nsn=\"localhost:8000\" c=127.0.0.1:56048 s=127.0.0.1:58115 ctx=/ clen=n/a"
A web handler threw an exception. Details:
no value
127.0.0.1 - - [23/Jun/2022:15:13:23 -0500] "GET /api/user/app/get HTTP/1.1" 500 51 "http://localhost:8000/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"
Right where the proper code execution stops, I tried to catch an error. But in vain. The error isn’t caught, the lines thereafter are never reached and the handler fails.
My code behaves as if verifyClaimsAt called finishWith, only that verifyClaimsAt isn’t aware of Snap or MonadSnap and thus can’t do that.
How do I go about nailing down this error?