Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected Auth interaction #1494

Open
Vlix opened this issue Dec 3, 2021 · 2 comments
Open

Unexpected Auth interaction #1494

Vlix opened this issue Dec 3, 2021 · 2 comments

Comments

@Vlix
Copy link

Vlix commented Dec 3, 2021

I have noticed a peculiar interaction with using the Auth API part. Even when you use a ReqBody afterwards in that same endpoint, the Auth handling will be done AFTER the ReqBody has been parsed/transformed. i.e.:

type MyApi = Auth [JWT] MyFields :> ReqBody '[JSON] MyBody :> Post '[PlainText] NoContent

In this case, even when the JWT fails to verify or when the header isn't even present, the endpoint will FIRST reply with 400 BAD CONTENT responses until the JSON is parsed correctly, and THEN the 401 UNAUTHORIZED I throw when the result of AuthResult is not Authenticated.

Is this the expected behaviour? Because from a security perspective, I would like to not leak my data format to any person that knows (or stumbles upon) my endpoints.

I would expect that it might work that way when you define ReqBody :> Auth, but even then I'd prefer the Auth to be checked first.

@Vlix
Copy link
Author

Vlix commented Dec 7, 2021

I think I found the problem. It's the authCheck in the HasServer instance for Auth.
The runAuth will happily return something other than Authenticated, but this doesn't actually throw a delayedFail(Fatal) in the DelayedIO section of that authCheck function, so it will happily first try and parse the request body before then passing the AuthResult to the handler and THEN let the user decide to throw a 401 UNAUTHORIZED or not.

I think the 401 should be thrown immediately if the jwtAuthCheck doesn't result in an Authenticated{}.
Possibly have the JWTSettings take a handler the user can pass in how to handle the AuthResult? If the user doesn't want the immediate 401 or maybe if they want to return something different (like a different response body?)


EDIT: Thinking about it a bit more, would it make more sense to change the ServerT definition to v -> ServerT api m (instead of the AuthResult v -> ServerT api m? Given there'd be a user-provided handler that would be AuthResult v -> DelayedIO v or AuthResult v -> Maybe ServerError or something else to decide how to short-circuit the handler?

@alpmestan
Copy link
Contributor

This reminds me of the Required/Optional and Strict/Lenient modifiers that we have for query params, request bodies, headers, etc, so I'd probably just reuse those and make the auth combinator more flexible, allowing modifiers to be given to it to determine how things should go. I'd say AuthResult v -> ... was a good default, because it's easy to implement "reject anything unauthenticated" on top of that, whereas with v -> ... you wouldn't be able to take unauthenticated requests and e.g hand back less data, like only public stuffs. But more flexibility using a pattern we've been applying elsewhere seems reasonable.

@tchoutri Food for thought for #1484 I guess.

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

No branches or pull requests

2 participants