Package Exports
- @xlock/node
- @xlock/node/express
- @xlock/node/fastify
- @xlock/node/hono
- @xlock/node/koa
- @xlock/node/next
Readme
@xlock/node
Invisible bot protection middleware for Node.js. Drop-in replacement for reCAPTCHA, Turnstile, and hCaptcha — no visual challenges, no user friction.
Supports Express, Fastify, Koa, Next.js, and Hono.
Install
npm install @xlock/nodeQuick Start
Express
import { xlockMiddleware } from "@xlock/node/express";
app.use("/api/auth", xlockMiddleware({
siteKey: "sk_...",
flows: [
{
slug: "login",
name: "Login",
flowType: "auth",
match: [{ method: "POST", pathPattern: "/api/auth/login" }],
},
],
}));Fastify
import { xlockPlugin } from "@xlock/node/fastify";
fastify.register(xlockPlugin, {
siteKey: "sk_...",
routes: ["/api/auth/*"],
});Next.js
// middleware.ts
import { withXlock } from "@xlock/node/next";
export const middleware = withXlock({
siteKey: process.env.NEXT_PUBLIC_XLOCK_SITE_KEY!,
flows: [
{
slug: "checkout",
match: [{ method: "POST", pathPattern: "/api/checkout" }],
},
],
});
export const config = { matcher: ["/api/:path*"] };Hono
import { xlockMiddleware } from "@xlock/node/hono";
app.use("/api/auth/*", xlockMiddleware({ siteKey: "sk_..." }));Koa
import { xlockMiddleware } from "@xlock/node/koa";
router.post("/api/auth/login", xlockMiddleware({ siteKey: "sk_..." }), loginHandler);Direct Verification
import { verify } from "@xlock/node";
const result = await verify("https://api.x-lock.dev", "sk_...", token, {
method: "POST",
path: "/api/login",
flowHint: "login",
});
if (result.blocked) {
console.log("Blocked:", result.reason);
}Configuration
All middleware accepts these options:
| Option | Type | Default | Description |
|---|---|---|---|
siteKey |
string |
XLOCK_SITE_KEY env |
Your x-lock site key |
apiUrl |
string |
https://api.x-lock.dev |
x-lock API endpoint |
failOpen |
boolean |
true |
Allow requests through on API errors |
flows |
Flow[] |
[] |
SDK-canonical flow declarations used to attach flowHint |
SDK-Canonical Flows
Declare flows in code, then register the module with the x-lock control plane:
import { defineFlowModule, registerFlowModule } from "@xlock/node";
await registerFlowModule({
apiKey: process.env.XLOCK_API_KEY!,
...defineFlowModule({
siteKey: process.env.XLOCK_SITE_KEY!,
appName: "web",
moduleVersion: "2026.04.14",
flows: [
{
slug: "login",
name: "Login",
flowType: "auth",
match: [{ method: "POST", pathPattern: "/api/login" }],
},
{
slug: "checkout",
name: "Checkout",
flowType: "payment",
match: [{ method: "POST", pathPattern: "/api/checkout" }],
},
],
}),
});Notes:
- Registration goes to the control plane at
https://x-lock.cloud/api/sdk/flow-modules/register. - Use a service account API key with the
flows:writescope. - Runtime enforcement still goes to
https://api.x-lock.dev. - The dashboard renders registered modules read-only; flow structure stays canonical in code.
How It Works
- Your frontend loads the x-lock script (invisible to users)
- x-lock runs proof-of-work + behavioral analysis in the background
- The script attaches a token to requests via the
x-lockheader - This middleware verifies the token server-side before your route handler runs
No CAPTCHAs. No clicking fire hydrants. No Google tracking.
Migrating from reCAPTCHA
- const { RecaptchaEnterpriseServiceClient } = require("@google-cloud/recaptcha-enterprise");
+ import { xlockMiddleware } from "@xlock/node/express";
- app.post("/login", async (req, res) => {
- const score = await recaptcha.assessToken(req.body.token);
- if (score < 0.5) return res.status(403).json({ error: "Bot detected" });
- // handle login
- });
+ app.post("/login", xlockMiddleware({ siteKey: "sk_..." }), (req, res) => {
+ // handle login — x-lock already verified the request
+ });License
MIT