CASE STUDY · /captcha-service
Self-Hosted Captcha Service
A drop-in reCAPTCHA alternative — server-side puzzle state, single-use JWT, siteverify-compatible API.
Overview
A self-hosted captcha service that replaced a leaky npm slider-captcha package — moving every piece of puzzle state server-side so positions and salts never reach the client.
The integration surface is intentionally identical to Cloudflare Turnstile / Google reCAPTCHA: script tag on the host, POST /v1/siteverify on the backend. Any team familiar with reCAPTCHA can adopt it without retraining.
The problem
The previous slider-captcha shipped puzzle solutions to the client — a 5-minute reverse-engineering job to bypass. Plus an external captcha provider was a single point of failure, observable by a third party, and not customizable.
What I built
- Puzzle state lives server-side; client never sees positions/salts
- Iframe-isolated challenge UI: only the iframe talks to /v1/internal/{generate,solve}
- Single-use JWT token lifecycle: issue → atomic consume against Redis (race-safe)
- siteverify API: drop-in shape compatible with reCAPTCHA — POST secret + token
- Layered defense: origin enforcement, IP allowlists, per-site rate limits, pluggable abuse rules
- MySQL for sites/audit/abuse logs; Redis for sessions/tokens
- Admin dashboard: sitekey/secret management, usage metrics, audit log viewer
Tech stack
Node.jsTypeScriptExpressRedisMySQLJWTReact (admin)
Outcome
Live in production guarding login/signup endpoints. Mean verify latency under 25ms. Zero successful replay attacks since launch — the atomic Redis consume catches every duplicate redemption attempt.
Want this in your stack? Let's talk.