I'm currently making a Scotty API and I couldn't find any examples of basicAuth implementations (Wai Middleware HttpAuth).
Specifically, I want to add basic auth headers (user, pass) to SOME of my endpoints (namely, ones that start with "admin"). I have everything set up, but I can't seem to make the differentiation as to which endpoints require auth and which ones don't. I know I need to use something like this, but it uses Yesod, and I wasn't able to translate it to Scotty.
So far, I have this:
routes :: (App r m) => ScottyT LText m ()
routes = do
-- middlewares
middleware $ cors $ const $ Just simpleCorsResourcePolicy
{ corsRequestHeaders = ["Authorization", "Content-Type"]
, corsMethods = "PUT":"DELETE":simpleMethods
}
middleware $ basicAuth
(\u p -> return $ u == "username" && p == "password")
"My Realm"
-- errors
defaultHandler $ \str -> do
status status500
json str
-- feature routes
ItemController.routes
ItemController.adminRoutes
-- health
get "/api/health" $
json True
But it adds authentication to all my requests. I only need it in some of them.
Thank you so much!
You can use the
authIsProtectedfield of theAuthSettingsto define a functionRequest -> IO Boolthat determines if a particular (Wai)Requestis subject to authorization by basic authentication. In particular, you can inspect the URL path components and make a determination that way.Unfortunately, this means that the check for authorization is completely separated from the Scotty routing. This works fine in your case but can make fine-grained control of authorization by Scotty route difficult.
Anyway, the
AuthSettingsare the overloaded"My Realm"string in your source, and according to the documentation, the recommended way of defining the settings is to use the overloaded string to write something like:That looks pretty horrible, but anyway, the
needsAuthfunction will have signature:so it can inspect the Wai
Requestand render a decision in IO on whether or not the page needs basic authentication first. CallingpathInfoon theRequestgives you a list of path components (no hostname and no query parameters). So, for your needs, the following should work:Note that these are the parsed non-query path components, so
/adminand/admin/and/admin/whateverand even/admin/?q=helloare protected, but obviously/administrator/...is not.A full example: