{
"turnstile": {
"siteKey": "1x00000000000000000000AA",
"secretEnv": "TURNSTILE_SECRET",
"paths": ["/contact/*"],
"forms": ["form#contact"]
},
"authProvider": {
"type": "dev",
"loginBaseUrl": "http://login.demo.localhost:3000",
"cookieDomain": "demo.localhost"
},
"routes": [{
"host": "app.demo.localhost", "path": "/*", "frontend": true,
"backend": "http://127.0.0.1:8080"
}]
}Turnstile protection
Two examples with Cloudflare’s test keys: a form (mode: forms) and
a whole-page gate (mode: gate). The test keys pass without a real
widget; replace them before deploying.
Form protection
[examples/turnstile/routes.json](/examples/turnstile/routes.json)
Whole-page gate
[examples/turnstile-gate/routes.json](/examples/turnstile-gate/routes.json)
{
"turnstile": {
"mode": "gate",
"siteKey": "1x00000000000000000000AA",
"secretEnv": "TURNSTILE_SECRET",
"paths": ["/*"],
"exemptPaths": ["/healthz"],
"clearanceTtlSeconds": 1800,
"challenge": { "appearance": "interaction-only" }
},
"routes": [{
"host": "app.demo.localhost", "path": "/*", "frontend": true,
"backend": "http://127.0.0.1:8080"
}]
}Run it
export TURNSTILE_SECRET=1x0000000000000000000000000000000AA
gate-one -check -config routes.json
gate-one -config routes.jsonforms: the widget is injected into
form#contact; a POST without a token is refused by Gate One.gate: the first visit shows "Checking your browser"; after the test challenge, the page is served and the clearance cookie lasts 30 minutes.
The source repository also ships a runnable demo (deploy/local/turnstile)
with a backend, ./run.sh gate and ./run.sh api.
Production checklist
create the widget in the Cloudflare dashboard and declare every public hostname;
put the secret in the environment of every replica (
TURNSTILE_SECRET), never in the file;keep a
rateLimiton the protected paths;restrict the application’s network access to Gate One: this check only covers traffic that goes through it;
document that the client IP is sent to Cloudflare;
decide whether the site must stay indexable (a
/*gate blocks crawlers).
Limits
the token is single-use: only Gate One verifies it;
a second ingress that reaches the application directly bypasses the check;
a gate on
/*blocks search engines.