Status: adopted 2026-08-04.
Signet does not contain a bot-scoring network, JavaScript fingerprinting service, CAPTCHA, or Clerk-style bot-detection switch. Do not describe a plain Signet instance as having bot detection. For a public hosted deployment, put an abuse-aware edge in front of it and keep Signet's own deterministic controls enabled. This guide uses Cloudflare because that is the measured deployment shape; another edge is acceptable only if it preserves the same boundaries.
The layers solve different problems:
| layer | what it can do | what it cannot prove |
|---|---|---|
| Cloudflare edge | absorb volumetric traffic; apply WAF, rate, and bot signals before origin work | account identity, credential correctness, or Signet lock state |
| Signet rate limiter | bound requests per source IP and exact auth path; optional PostgreSQL storage coordinates processes | identify bots or absorb traffic before it reaches the origin |
| Signet account lockout | persistently bound failed password attempts per canonical identity across IPs/processes | distinguish a bot from a forgetful person |
| email/disposable policy | refuse configured identity-creation inputs | stop automation using acceptable addresses |
Edge protection is defense in depth. It does not replace [rate_limit], [lockout], [email_policy], or [disposable_email].
Multi-node Signet deployments should use [rate_limit] storage = "database" as described in the rate-limiting guide. That closes process-local quota splitting; it does not replace an edge because every refused request has still reached the origin and consumed a database operation.
Required Cloudflare boundary
- Proxy the authentication hostname in Cloudflare. Prevent a client from reaching the origin around Cloudflare: prefer Cloudflare Tunnel or a per-zone/per-hostname Authenticated Origin Pull; otherwise restrict the origin firewall to current Cloudflare address ranges. A proxied DNS record alone does not close an origin-IP bypass.
- At the last trusted proxy before Signet, accept
CF-Connecting-IPonly from an authenticated or allowlisted Cloudflare source and replaceX-Forwarded-Forwith that one value. Never append an incomingX-Forwarded-For. Signet uses the first value as its limiter identity; preserving a client-supplied first value lets the client choose fresh buckets or charge a victim's bucket. - Preserve the public
Host, set[server] base_urlto the outer HTTPS origin, and follow the scheme-header rules in the reverse-proxy guide. Bot controls do not repair a broken proxy trust boundary. - Verify from outside the origin network that the public origin works, direct-origin requests fail, and two different clients arrive in different Signet rate-limit buckets.
Cloudflare documents CF-Connecting-IP as the consistent, single-valued visitor address and recommends it over X-Forwarded-For at the origin. This is why the rewrite above is deliberate, not an interchangeable header preference.
Edge rules: start narrow
Match the configured hostname, HTTP method, and exact deployed [server] base_path; the default paths below therefore begin with /api/auth. Confirm real paths in Cloudflare analytics before enforcing a rule.
Start with observation, then rate-limit high-cost unauthenticated writes such as:
POST /api/auth/sign-in/email,/sign-in/username, and/sign-up/email;- password-reset and verification sends, including
/request-password-reset,/send-verification-email, and/email-otp/send-verification-otp; - OTP/code verification and anonymous identity creation; and
- the browser pages
/login,/sign-up, and/forgot-passwordwhen they are enabled.
Choose thresholds from observed legitimate traffic and NAT/mobile concentration, not by copying a sample number. Prefer counting failed responses when the Cloudflare plan and route response shape make that possible. Keep Signet's lower, deterministic endpoint budgets enabled: edge counters can reset or change independently and Signet's account lockout covers attacks distributed across IPs.
Roll out each rule in this order:
- log/observe;
- rate-limit or challenge a small browser-only cohort;
- verify password, OAuth callback, OTP, reset, mobile, API-client, monitoring, and IPv6 flows; and
- expand while watching Cloudflare events plus Signet
429,retry-after, andaccount.lockedtelemetry.
Do not turn on a blanket cache rule for the authentication hostname as part of this work. Bypass cache for state-changing auth APIs and callback routes; treat the public docs and OIDC discovery/JWKS documents as separate, deliberately reviewed cache policies.
Challenges are not transparent to API clients
Cloudflare's free Bot Fight Mode is not the default recommendation for an auth hostname. It covers the whole domain, cannot be skipped with WAF custom rules, and Cloudflare warns that it may challenge API or mobile traffic. A better-auth client expects JSON from auth routes; an injected HTML/JavaScript challenge is a protocol failure even when it blocks a bot.
Use narrowly scoped WAF/rate-limiting actions for JSON routes. Use Managed Challenge only where the request is an actual browser navigation/form flow and the complete client matrix has passed. If a deployment needs bot-product exceptions, use a Cloudflare product whose rules can be skipped for the affected API, callback, health, and monitoring paths; do not assume Bot Fight Mode exceptions exist.
Turnstile is also not integrated into Signet. A widget by itself is not protection: Cloudflare requires server-side Siteverify validation, and its tokens are single-use and expire after five minutes. Adding a widget to an application page does not protect clients that call Signet's public JSON endpoint directly. A customer-specific application or edge Worker may validate Turnstile before granting one application action, but that is a separate online integration, requires its own secret/outbound availability, and must not be represented as a Signet capability.
Truthful claim boundary
Allowed:
This deployment places Cloudflare WAF/rate controls in front of Signet and retains Signet's built-in rate limits, persistent account lockout, and email-admission policy.
Sources retrieved 2026-08-04
- Cloudflare Bot Fight Mode considerations and inability to skip rules:
https://developers.cloudflare.com/bots/get-started/bot-fight-mode/ - Cloudflare WAF rate-limiting guidance for login, credential-stuffing, OTP, and REST endpoints:
https://developers.cloudflare.com/waf/rate-limiting-rules/best-practices/ - Cloudflare visitor-IP header contract:
https://developers.cloudflare.com/fundamentals/reference/http-headers/ - Cloudflare origin protection options:
https://developers.cloudflare.com/fundamentals/security/protect-your-origin-server/ - Cloudflare Turnstile server-side validation contract:
https://developers.cloudflare.com/turnstile/get-started/server-side-validation/