Skip to content

rethinking guards #223

@terrablue

Description

@terrablue

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:

  1. Add all to primate/route to 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 .all instead of .get etc., and it raises confusing questions about what should happen if you call both route.all and route.get. It is not at all clear if .get should override or be suppressed, and probably the sensible choice would be to error on startup.
  2. Have guards behave differently from normal routes: add route.guard (or another mechanism), and a +guard.ts file must call this function. This would be a hard guarantee that when you create a +guard.ts file, 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions