Two drop-in components — server-side PNG images backed by MongoDB, or a fully browser-side canvas variant. No third-party services required.
Interactive demo
Works immediately. No backend, no database, no API calls. Copy the component and drop it in.
import { useRef } from 'react'; import CanvasCaptcha from './CanvasCaptcha'; function ContactForm() { const captchaRef = useRef(null); const handleSubmit = (e) => { e.preventDefault(); // validate() returns true/false // auto-redraws on wrong answer if (!captchaRef.current.validate()) return; // ✓ safe to submit }; return ( <form onSubmit={handleSubmit}> <CanvasCaptcha ref={captchaRef} /> <button type="submit">Send</button> </form> ); }
npm install needed. Copy CanvasCaptcha.jsx and you're done.Images generated server-side. Answers stored in MongoDB. The browser never sees the solution.
import { useState } from 'react'; import ServerCaptcha from './ServerCaptcha'; function LoginForm() { const [captcha, setCaptcha] = useState(null); const [reset, setReset] = useState(0); const handleSubmit = async (e) => { e.preventDefault(); if (!captcha) return; const res = await fetch('/api/login', { method: 'POST', body: JSON.stringify({ captcha_token_id: captcha.tokenId, captcha_answer: captcha.answer, }), }); if (!res.ok) setReset(r => r + 1); }; return ( <form onSubmit={handleSubmit}> <ServerCaptcha apiUrl="http://localhost:8080" onReady={setCaptcha} resetTrigger={reset} /> </form> ); }
POST /captcha/verify. The browser never sees the solution.Production-ready defaults. No config required.
The correct code is stored in MongoDB only. Only a distorted PNG image is returned to the client.
Each token is marked used immediately on first correct verification. Replay attacks are impossible.
MongoDB TTL index auto-deletes tokens after TOKEN_TTL_MINUTES (default 5). No cron jobs needed.
Sliding 60-second window blocks brute-force image generation. Default: 15 requests/min/IP.
/captcha/verify requires an X-API-Key header. Only your backend can call it — not the browser.
secrets.compare_digest prevents timing attacks on the API key check.
Docker Compose spins up the service and MongoDB together.
# 1. Clone the repo git clone https://github.com/ajaykumarvarma/EasyCaptcha.git cd easycaptcha # 2. Generate a strong secret key python -c "import secrets; print(secrets.token_hex(32))" # → paste the output as API_SECRET_KEY in docker/docker-compose.yml # 3. Start (MongoDB included) docker compose -f docker/docker-compose.yml up --build
Service live at http://localhost:8080 · Docs at http://localhost:8080/docs