Problem
Section titled “Problem”Sign-in returns captcha_required with details like:
{ "error": "captcha_required", "details": { "provider": "turnstile", "site_key": "0x4AAA...", "action": "login" }}The platform's risk engine has flagged this attempt as potentially automated and is demanding a human-verification challenge before letting it through.
One or more of:
- The IP address has a poor reputation (known bot, anonymising VPN, datacenter).
- Many failed sign-ins from this IP recently (brute-force defence).
- The fingerprint confidence is very low (private mode, fingerprinting blocked, headless browser).
- The tenant has captcha-on-every-login enabled.
Resolution
Section titled “Resolution”If you're using the React SDK
Section titled “If you're using the React SDK”The SDK renders the captcha automatically when the response asks for it. You don't write any code for the happy path — the user sees the challenge, completes it, sign-in continues.
If it's NOT rendering, check:
- The captcha provider's script is allowed by your CSP. Add the provider's domain (
challenges.cloudflare.comfor Turnstile,www.google.com/recaptchafor reCAPTCHA) to yourscript-src. - The provider's iframe is allowed. Add to your
frame-srcsimilarly.
If you're driving the flow by hand
Section titled “If you're driving the flow by hand”Render the captcha widget with the site_key returned in the response. When the user completes it, your code receives a token from the provider. Re-submit the sign-in with the token attached:
POST /api/v1/auth/login{ "email": "anita@cymmetri.com", "password": "...", "captcha": { "provider": "turnstile", "token": "<token-from-provider>" }}The platform verifies the token with the provider on its side; on success the sign-in proceeds.
Persistent captcha for a specific user
Section titled “Persistent captcha for a specific user”If a real human keeps being challenged, their IP / device is being scored as suspicious. Check:
- Are they on a VPN? Many corporate VPNs share IPs across thousands of users — false positive likely.
- Is fingerprinting blocked? Aggressive privacy settings (some Brave / Firefox configurations) confuse the fingerprint signal.
- Was there a recent burst of failed sign-ins from their IP?
Adjust the tenant's risk-policy settings if the false-positive rate is unacceptable for your user base.
Headless / programmatic clients
Section titled “Headless / programmatic clients”CI tests, machine-to-machine integrations, anything without a UI to render a captcha — these should not use the user-password sign-in path at all. Use client credentials instead. Client credentials skips captcha because there's no human in the loop and the auth model is different.
When the captcha provider itself is down
Section titled “When the captcha provider itself is down”Cloudflare Turnstile, reCAPTCHA — both have rare outages. The platform falls back to refusing sign-ins (fail-closed) when its captcha verification fails. Two paths:
- Wait it out. Outages of major providers are typically < 1 hour.
- Configure a fallback in the tenant's risk policy (e.g., allow sign-in with a one-time email code instead of captcha during provider outages).
The audit log records captcha.provider_unreachable events when this happens.