-
Notifications
You must be signed in to change notification settings - Fork 11
Closed
Description
Guards execute before routes, recursively, from outer (top) to lower guards. They represent checks whether a given request may access a given route.
They use the same route syntax as all other routes, and indicate a pass-through by returning (explicitly -- no coercion) null:
import response from "primate/response";
import route from "primate/route";
route.get(request => {
if (request.headers.get("Authorization") !== "opensesame") {
return response.redirect("/somewhere-else");
}
// explicit pass
return null;
});There's a bit of a problem here. This guard only applies to GET route functions, which means that any .post, .put etc. route functions within its directory or below won't be guarded by it.
As this is security-related, this kind of behaviour can turn into a footgun.
As far as I can see there are two options here:
- Add
alltoprimate/routeto indicate that a route function applies to all verbs. This wouldn't be limited to guards but could be used by normal routes, as well as error and layout files. But the clearest use case are guards.
However, this is no guarantee the user will use.allinstead of.getetc., and it raises confusing questions about what should happen if you call bothroute.allandroute.get. It is not at all clear if.getshould override or be suppressed, and probably the sensible choice would be to error on startup. - Have guards behave differently from normal routes: add
route.guard(or another mechanism), and a+guard.tsfile must call this function. This would be a hard guarantee that when you create a+guard.tsfile, you will use it (mostly sensibly, hopefully).
This option would also allow us to rethink how a guard lets someone in, and perhaps reverse the logic: throwing an error means preventing entry, and otherwise the user would have a way to pass data onto the next route (or guard).
That would be particularly useful to use guards as a way to preauth access tokens, in APIs.