Sign inSign up

f3ktech/recaptcha-v3-verifier

By f3ktech

β€’Updated 10 months ago

Securely validates Google reCAPTCHA v3 tokens server-side. Hardened container runtime.

Image
0

2.4K

f3ktech/recaptcha-v3-verifier repository overview

⁠reCAPTCHA v3 Verifier Microservice

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).

⁠Features

  • πŸ”’ Secure reCAPTCHA v3 token verification
  • 🐳 Docker-ready with multi-stage builds
  • ☸️ Complete Kubernetes Helm chart
  • πŸ₯ Health and readiness probes
  • πŸ“Š Horizontal Pod Autoscaling
  • πŸ” Non-root container execution
  • πŸš€ Production-ready with security best practices
  • πŸ‘₯ Optional multi-account support via account-specific env vars

⁠API Endpoints

⁠POST /verify

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"
}
⁠GET /health

Health check endpoint for liveness probe.

⁠GET /ready

Readiness check endpoint. Returns 200 when at least one account is configured.

⁠GET /accounts

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
}

⁠Local Development

⁠Prerequisites
  • Node.js 24+
  • Docker (optional)
⁠Setup
  1. Install dependencies:
npm install
  1. Create .env file:
cp .env.example .env
  1. Configure your .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
  1. Run locally:
npm start
# or with auto-reload
npm run dev

⁠Docker

⁠Build Image
docker build -t recaptcha-v3-verifier:latest .
⁠Run Container
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
⁠Docker Compose (Local)
# 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"}'

⁠Configuration

⁠Environment Variables
VariableDescriptionDefaultRequired
RECAPTCHA_SECRET_KEYGoogle reCAPTCHA secret key-Yes
ALLOWED_ORIGINSComma-separated CORS origins*No
ALLOW_SCOREScore to automatically allow (0.0-1.0)0.6No
CHALLENGE_SCOREScore to challenge (0.0-1.0). Requests below this are denied.0.3No

Multi-account (optional): define account-specific overrides by suffixing the account ID.

VariableDescription
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)
⁠Decision Logic
  • allow when score >= ALLOW_SCORE
  • challenge when CHALLENGE_SCORE <= score < ALLOW_SCORE
  • deny when score < CHALLENGE_SCORE

⁠Security Features

  • βœ… Non-root user execution
  • βœ… Read-only root filesystem
  • βœ… Dropped capabilities
  • βœ… Security headers via Helmet.js
  • βœ… CORS protection
  • βœ… Secret management via Kubernetes Helm Chart and Secrets
  • βœ… Resource limits and requests

⁠Monitoring

⁠Metrics

The service logs verification events with:

  • Timestamp
  • Account ID
  • Score
  • Action
  • Decision (allow/challenge/deny)
  • Hostname
⁠Backward Compatibility
  • If only RECAPTCHA_SECRET_KEY is set, it is used as the default account.
  • /verify accepts the same request body; accountId is optional.
  • If no default account is configured and no accountId is provided, /verify returns HTTP 500 (service configuration error), matching previous behavior.

⁠Troubleshooting

⁠CORS errors

Update ALLOWED_ORIGINS in the secret to include your frontend domain

⁠License

MIT

Tag summary

Content type

Image

Digest

sha256:48e78987c…

Size

59.7 MB

Last updated

10 months ago

docker pull f3ktech/recaptcha-v3-verifier