Ring handlers over the ceremony, and the same handlers as reitit route data for a host that wants them mounted rather than wired.
The host supplies one view. It is called with the request and one of three
states — {}, {:sent? true}, {:spent? true} — and returns whatever that
host's renderer accepts as a :body: Hiccup under web-base, a string under
plain Ring. That is the whole of what this module knows about pages.
Three details are security, not ergonomics:
The redemption never renders. A link opened from a page carries its URL to
whatever that page loads next, so a token in a Referer reaches every third
party the landing page touches. The redemption answers 303 and nothing
else, always, and says Referrer-Policy: no-referrer on its own so a host
without web-base's headers is no worse off.
The token is read from the URI, not from a router's path parameters. It means a host mounts these handlers under any router or none, and it means there is no naming convention to get wrong.
The POST does the same work whatever the address is — it cannot do
otherwise, because issue! never asks whether the address is known — and
answers the same 303 either way (SPEC §11).
Ring handlers over the ceremony, and the same handlers as reitit route data
for a host that wants them mounted rather than wired.
The host supplies **one** view. It is called with the request and one of three
states — `{}`, `{:sent? true}`, `{:spent? true}` — and returns whatever that
host's renderer accepts as a `:body`: Hiccup under web-base, a string under
plain Ring. That is the whole of what this module knows about pages.
Three details are security, not ergonomics:
**The redemption never renders.** A link opened from a page carries its URL to
whatever that page loads next, so a token in a `Referer` reaches every third
party the landing page touches. The redemption answers `303` and nothing
else, always, and says `Referrer-Policy: no-referrer` on its own so a host
without web-base's headers is no worse off.
**The token is read from the URI**, not from a router's path parameters. It
means a host mounts these handlers under any router or none, and it means
there is no naming convention to get wrong.
**The POST does the same work whatever the address is** — it cannot do
otherwise, because `issue!` never asks whether the address is known — and
answers the same `303` either way (SPEC §11).(handlers ceremony
{:keys [view login-path logout-path after-login after-logout field
rate-limit]
:as opts})The four handlers, as a map. Mount them yourself, or hand the same options
to routes.
:view (fn [request state]) → a :body (required)
:login-path where the form lives (required)
:logout-path where the logout POST goes (default "/logout")
:after-login where a redeemed link lands (default "/")
:after-logout where a logout lands (default :login-path)
:field the form field holding the identifier (default "identifier")
:rate-limit {:limit n :window-ms n}, or a (fn [key] boolean), or
absent for no limit. The key is the request's :remote-addr,
which is a proxy's address unless the host is told to trust
X-Forwarded-For. The map inherits the ceremony's clock
unless it names its own.
The POST handler reads :form-params, so the host's stack must have parsed
the body — ring.middleware.params/wrap-params, which web-base already
applies. CSRF is the host's too, for the same reason: web-base has it, and a
bare Ring host must bring it.
The four handlers, as a map. Mount them yourself, or hand the same options
to `routes`.
:view (fn [request state]) → a `:body` (required)
:login-path where the form lives (required)
:logout-path where the logout POST goes (default "/logout")
:after-login where a redeemed link lands (default "/")
:after-logout where a logout lands (default `:login-path`)
:field the form field holding the identifier (default "identifier")
:rate-limit `{:limit n :window-ms n}`, or a `(fn [key] boolean)`, or
absent for no limit. The key is the request's `:remote-addr`,
which is a proxy's address unless the host is told to trust
`X-Forwarded-For`. The map inherits the ceremony's clock
unless it names its own.
The POST handler reads `:form-params`, so the host's stack must have parsed
the body — `ring.middleware.params/wrap-params`, which web-base already
applies. CSRF is the host's too, for the same reason: web-base has it, and a
bare Ring host must bring it.(routes ceremony opts)The same handlers as reitit route data, so a host composes them with
(into (auth/routes ceremony opts) my-routes). This is data — vectors and
maps — and costs no dependency: reitit is the host's, not this module's.
The same handlers as reitit route data, so a host composes them with `(into (auth/routes ceremony opts) my-routes)`. This is data — vectors and maps — and costs no dependency: reitit is the host's, not this module's.
(unauthorized ceremony)(unauthorized ceremony challenge)The 401 SPEC §14 asks this module for. web-base declines to emit one
because a proper 401 carries WWW-Authenticate and only whoever
authenticates knows the scheme — so here it is, named after the ceremony
rather than after a password. A host mounting these handlers for an API
answers with this instead of redirecting a browser that isn't there.
challenge overrides the default for a host whose clients expect another.
The `401` SPEC §14 asks this module for. web-base declines to emit one because a proper `401` carries `WWW-Authenticate` and only whoever authenticates knows the scheme — so here it is, named after the ceremony rather than after a password. A host mounting these handlers for an API answers with this instead of redirecting a browser that isn't there. `challenge` overrides the default for a host whose clients expect another.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |