Securely validates Google reCAPTCHA v3 tokens server-side. Hardened container runtime.
2.4K
A lightweight Node.js microservice that securely validates Google reCAPTCHA v3 tokens server-side and returns an allow/challenge/deny decision based on configurable score thresholds. Hardened container runtime (distroless Node.js 24, non-root) with baseline app hardening (Helmet headers, CORS controls).
Verify a reCAPTCHA v3 token and return a decision.
Request:
{
"token": "recaptcha_token_here",
"action": "optional_action_name",
"accountId": "optional_account_id"
}
Response (examples):
Allow
{
"success": true,
"accountId": "default",
"decision": "allow",
"allow": true,
"challenge": false,
"deny": false,
"score": 0.9,
"action": "submit",
"thresholds": { "allow": 0.6, "challenge": 0.3 },
"challenge_ts": "2025-12-12T10:00:00Z",
"hostname": "yourdomain.com"
}
Challenge
{
"success": true,
"accountId": "default",
"decision": "challenge",
"allow": false,
"challenge": true,
"deny": false,
"score": 0.42,
"action": "submit",
"thresholds": { "allow": 0.6, "challenge": 0.3 },
"challenge_ts": "2025-12-12T10:00:00Z",
"hostname": "yourdomain.com"
}
Deny
{
"success": true,
"accountId": "default",
"decision": "deny",
"allow": false,
"challenge": false,
"deny": true,
"score": 0.12,
"action": "submit",
"thresholds": { "allow": 0.6, "challenge": 0.3 },
"challenge_ts": "2025-12-12T10:00:00Z",
"hostname": "yourdomain.com"
}
Health check endpoint for liveness probe.
Readiness check endpoint. Returns 200 when at least one account is configured.
List configured account IDs and their thresholds.
Response
{
"success": true,
"accounts": [
{ "accountId": "default", "allowScore": 0.6, "challengeScore": 0.3 },
{ "accountId": "account1", "allowScore": 0.7, "challengeScore": 0.4 }
],
"totalAccounts": 2
}
npm install
.env file:cp .env.example .env
.env:RECAPTCHA_SECRET_KEY=your_secret_key
ALLOWED_ORIGINS=http://localhost:3000
ALLOW_SCORE=0.6
CHALLENGE_SCORE=0.3
# Optional additional accounts (suffix with _<accountId>)
# RECAPTCHA_SECRET_KEY_account1=your_account1_secret
# ALLOW_SCORE_account1=0.7
# CHALLENGE_SCORE_account1=0.4
npm start
# or with auto-reload
npm run dev
docker build -t recaptcha-v3-verifier:latest .
docker run -p 3000:3000 \
-e RECAPTCHA_SECRET_KEY=your_secret_key \
-e ALLOWED_ORIGINS=http://localhost:3000 \
-e ALLOW_SCORE=0.6 \
-e CHALLENGE_SCORE=0.3 \
# Optional additional accounts
# -e RECAPTCHA_SECRET_KEY_account1=your_account1_secret \
# -e ALLOW_SCORE_account1=0.7 \
# -e CHALLENGE_SCORE_account1=0.4 \
recaptcha-v3-verifier:latest
# Copy env template and set your secret
cp .env.example .env
# Edit .env to set RECAPTCHA_SECRET_KEY, ALLOWED_ORIGINS, ALLOW_SCORE, CHALLENGE_SCORE
# Build and start
docker compose up --build
# Tail logs
docker compose logs -f
# Stop
docker compose down
Test the API locally:
curl -X POST http://localhost:3000/verify \
-H "Content-Type: application/json" \
-d '{"token":"test_token"}'
# With an explicit accountId (if you configured additional accounts)
curl -X POST http://localhost:3000/verify \
-H "Content-Type: application/json" \
-d '{"token":"test_token","accountId":"account1"}'
| Variable | Description | Default | Required |
|---|---|---|---|
RECAPTCHA_SECRET_KEY | Google reCAPTCHA secret key | - | Yes |
ALLOWED_ORIGINS | Comma-separated CORS origins | * | No |
ALLOW_SCORE | Score to automatically allow (0.0-1.0) | 0.6 | No |
CHALLENGE_SCORE | Score to challenge (0.0-1.0). Requests below this are denied. | 0.3 | No |
Multi-account (optional): define account-specific overrides by suffixing the account ID.
| Variable | Description |
|---|---|
RECAPTCHA_SECRET_KEY_<accountId> | Secret key for a specific account (e.g., RECAPTCHA_SECRET_KEY_account1) |
ALLOW_SCORE_<accountId> | Optional per-account allow threshold (falls back to ALLOW_SCORE) |
CHALLENGE_SCORE_<accountId> | Optional per-account challenge threshold (falls back to CHALLENGE_SCORE) |
allow when score >= ALLOW_SCOREchallenge when CHALLENGE_SCORE <= score < ALLOW_SCOREdeny when score < CHALLENGE_SCOREThe service logs verification events with:
RECAPTCHA_SECRET_KEY is set, it is used as the default account./verify accepts the same request body; accountId is optional.accountId is provided, /verify returns HTTP 500 (service configuration error), matching previous behavior.Update ALLOWED_ORIGINS in the secret to include your frontend domain
MIT
Content type
Image
Digest
sha256:48e78987cβ¦
Size
59.7 MB
Last updated
10 months ago
docker pull f3ktech/recaptcha-v3-verifier