Documentation menuHono

Hono

A Hono middleware for Bun, Node, Deno and Workers runtimes.

Add the script, a hidden blockalt-token field and a submit handler in a static file (no inline script needed):

HTML
<script src="https://blockalt.click/v1/assets/blockalt.c8b2d9539dbbc932999adb0f51a36bddd4e99899f543e1505818841878cf9813.js"
  integrity="sha384-pblByFDqcJxRfhDh18GH3gRsWy9ZaS4AjDc6OpozzQqvkuYvyin+4BWcKXxA+bN8"
  crossorigin="anonymous"></script>
<script src="/js/signup.js" defer></script>

<form id="signup" method="post" action="/signup">
  <input name="email" type="email" required>
  <input name="blockalt-token" type="hidden">
  <button>Create account</button>
  <p class="error" role="alert"></p>
</form>
js/signup.jsJavaScript
const protection = BlockAlt.create({
  siteKey: "ba_pk_your_public_site_key",
  apiUrl: "https://blockalt.click",
  // Every key of GET /v1/keys (configPublicKeys), standby keys included.
  configPublicKeys: ["MCowBQYDK2VwAyEAXmYdcBh/jf+z+0H+hs2QvZ9UG4PBgkRvHX/JuXyjIL8=","MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE34qdEtOeD21+CmmfTmFyRr/vySsY1TD6BJZFtwF37pkelvN2vRYWWHdLrUouzkQXEfnA7V50xK2QcmnBCGsxbA==","MCowBQYDK2VwAyEAtkfghYcdvSRf2wA01gjQtgTqdYGjaDUZsOPXzgLnnT0=","MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYYmQNAMnVKK7G3VVguAk3SC/RFT5SDjCoxcFMOPFx0vmsGycJWOK8hCdxuTCHlvShng1fo0y4Q9PJHPIGQ9EfA=="],
});
const form = document.querySelector("#signup");
form.addEventListener("submit", async (event) => {
  event.preventDefault();
  try {
    // A fresh token for every attempt: single use, valid for 120 seconds.
    form.elements["blockalt-token"].value = await protection.execute("signup");
    form.submit();
  } catch {
    form.querySelector(".error").textContent = "Please try again.";
  }
});

Middleware #

blockalt.tsTypeScript
import { createMiddleware } from "hono/factory";

export const requireBlockAlt = (action: string) =>
  createMiddleware<{ Bindings: { BLOCKALT_SECRET: string } }>(async (c, next) => {
    const form = await c.req.parseBody(); // cached, the handler can read it again
    const token = typeof form["blockalt-token"] === "string" ? form["blockalt-token"] : "";
    let ok = false;
    try {
      const response = await fetch("https://blockalt.click/v1/siteverify", {
        method: "POST",
        redirect: "error",
        headers: { Authorization: `Bearer ${c.env.BLOCKALT_SECRET}`, "Content-Type": "application/json" },
        body: JSON.stringify({ token, hostname: "example.com", action }),
        signal: AbortSignal.timeout(3000),
      });
      ok = response.ok && (await response.json()).success === true;
    } catch {}
    if (!ok) return c.text("Please try again.", 403);
    await next();
  });
app.tsTypeScript
app.post("/signup", requireBlockAlt("signup"), async (c) => {
  const form = await c.req.parseBody();
  // …create the account
  return c.redirect("/welcome", 303);
});

On Node or Bun, read the secret from process.env instead of c.env.

Something unclear or missing on this page? Write to support@blockalt.click.