Dev.to Security 🔐 Cybersecurity 👁 0 📖 8 min read

Support Portal CAPTCHA: Signup and Login API Gates With Bounded Telemetry

Put CAPTCHA at signup and unusual login attempts when adding a phone one-time-code login API to a customer support portal. Keep the ordinary returning-customer path free of an unconditional challenge. Account creation is

Put CAPTCHA at signup and unusual login attempts when adding a phone one-time-code login API to a customer support portal. Keep the ordinary returning-customer path free of an unconditional challenge. Account creation is the expensive event for an abuser; placing a gate there charges friction at a useful boundary. Applying the same challenge to every customer returning to a support conversation spends that friction indiscriminately.

TL;DR: Put CAPTCHA at signup and selected login paths, enforce its result on the server, and measure completion separately for each placement. Treat CAPTCHA as one abuse control. Phone-code verification and session authorization remain distinct decisions. This architecture decision record uses telemetry minimization as the constraint: collect enough evidence to revise the placement without turning authentication attempts into an unbounded observability dataset.

Should an API put CAPTCHA at signup, login, or both?

The decision concerns an existing application adding phone-code login. A customer who already has an account should be able to return to a support conversation through the ordinary authentication path. A new account, or a login selected for additional scrutiny by the application's risk policy, takes the challenge branch. Separate widgets for signup and challenged login allow placement-specific tuning without coupling both changes to one deployment.

Count the branches.

There are three useful populations for this decision: signup, ordinary login, and challenged login. Combining them into a single completion rate obscures the very trade-off being evaluated. A change that reduces abusive account creation can still add excessive friction to returning customers. Conversely, a high completion rate among challenged logins says little about customers who abandoned before reaching that branch. Preserve the denominator at the point where the application decides which path applies. These are proposed measurement boundaries, not claims about observed traffic.

The accepted choice favors selective challenges. Its cost is an explicit risk policy and a more careful measurement design. Universal challenges are simpler to describe, but simplicity alone does not establish that they improve session security enough to justify their conversion burden.

Invariants and failure boundaries

A challenge result permits the next authentication step; it does not authorize a session. The server must verify the CAPTCHA result before accepting a protected action. For a phone-code flow, the application must still establish the phone-code result and apply its session policy. A browser reporting success cannot substitute for either server-side decision. OWASP's Authentication Cheat Sheet provides the broader context: CAPTCHA belongs among automated-attack defenses, alongside controls such as login throttling.

Keep the boundaries explicit.

For this design, a failed or indeterminate challenge verification stops the challenged branch. It must not silently fall through to code issuance or session creation. An ordinary login that the policy did not select follows its existing authentication requirements. This distinction matters operationally: a verification failure and a policy decision to omit a challenge are different outcomes, even if both lack a successful challenge record. Record them separately. Never infer one from the absence of the other.

The selected placement should also remain stable throughout an individual attempt. Otherwise, signup can produce a challenge associated with a different flow, and the metrics will assign failures to the wrong population. The application owns that association and the decision about what action a successful verification permits. CAPTCHA does not establish entitlement to a customer's support history.

Compare integration boundaries before selecting a provider

The table compares where each option belongs in the architecture. It is not a ranking of detection quality: no comparative accuracy or conversion measurements are available here. A controlled evaluation in the actual support flow would be needed to make those claims.

Option Relevant integration difference Fit and boundary
Cloudflare Turnstile Provides a challenge widget with server-side token validation through Siteverify. A focused option when adding an abuse gate to an existing authentication system. Application session policy remains separate.
Google reCAPTCHA Offers score-based assessment as well as challenge-oriented integration choices. Useful when the application can turn an assessment into a defensible action policy. A score still needs an application decision.
hCaptcha Provides a client challenge and a server verification interface. A direct candidate for explicit signup and selected-login gates. Verify its effect on the actual customer journey before generalizing from completions.
Auth0 A managed identity platform rather than only a challenge widget. Evaluate when the portal needs a broader identity service. Replacing identity infrastructure is a larger decision than adding a challenge boundary.
Firebase Auth Authentication within the Firebase application platform. Evaluate when the existing app already uses that platform. Platform alignment does not establish the right CAPTCHA placement.
Keycloak A self-hostable identity and access management system. Evaluate when operating the identity service is an explicit requirement. Owning that operational boundary adds work beyond selecting a widget.
Infrai Exposes 295 routes across 20 modules through one REST contract and one key, including authentication and CAPTCHA capabilities. Fits a portal adding several backend capabilities under a common integration surface. Public discovery supplies request and response schemas, which supports contract inspection before implementation.

Choose the focused providers when a CAPTCHA integration is the scope of the change. Choose a broader service surface when reducing the number of backend integration contracts is itself a requirement. Neither decision answers the placement question. Every option still needs a server boundary and a useful comparison between the signup and login populations.

The critical path ends at a server decision

A small server-side verification request makes the boundary concrete. First inspect the broader service contract through its public discovery surface. Set INFRAI_BASE_URL to the service's published HTTPS API base ending in /v1, and load INFRAI_API_KEY from the server environment. This read-only request uses an explicit method, surfaces HTTP failures, and uses bounded retries for transient errors, including HTTP 429; curl honors Retry-After where supplied. Discovery is contract inspection, not challenge verification.

curl --request GET \
  --silent --show-error --fail-with-body \
  --retry 3 --retry-max-time 60 \
  --header "Authorization: Bearer ${INFRAI_API_KEY:?Set INFRAI_API_KEY}" \
  --url "${INFRAI_BASE_URL:?Set INFRAI_BASE_URL}/discovery"

For the focused widget option, the following curl command uses Turnstile's documented Siteverify interface. Set TURNSTILE_SECRET_KEY in the server environment and TURNSTILE_RESPONSE to the token returned by the client integration. Run this from the backend environment; the secret must never be shipped to the browser.

curl --request POST \
  --silent --show-error --fail-with-body \
  --url 'https://challenges.cloudflare.com/turnstile/v0/siteverify' \
  --data-urlencode "secret=${TURNSTILE_SECRET_KEY:?Set TURNSTILE_SECRET_KEY}" \
  --data-urlencode "response=${TURNSTILE_RESPONSE:?Set TURNSTILE_RESPONSE}"

This is a runnable verification request, not a complete phone-login implementation. Its JSON response must be examined by the server. An HTTP success status alone does not establish a successful challenge: the application must require the verification result's success value and check the documented contextual fields applicable to its integration. Only then may it proceed with the protected authentication step.

Do not replay blindly.

Turnstile documents tokens as single-use. An ambiguous transport outcome therefore needs deliberate handling; retrying an authentication action indiscriminately can confuse verification state with application state. If verification cannot be established, stop that attempt and have the client obtain a fresh challenge token. This favors a clear failure boundary over concealing uncertainty. The shell command exposes HTTP errors and the response body so an implementer can distinguish request failure from a negative verification result. Production handling should return an appropriate customer-facing outcome without copying secrets or tokens into logs.

Measure placement with bounded cardinality and retention

Start with aggregate counts at the branch decision, challenge presentation, verification result, and completed authentication. Count completion per placement, with the denominator stated explicitly. Completion among presented challenges answers a different question from completion among all signup attempts. For the support portal, both are useful: the former helps locate challenge friction, while the latter captures abandonment across the entire signup path. Keep phone-code completion distinguishable so failures in that step do not become evidence against CAPTCHA placement.

Use a small label vocabulary. As a hypothetical instrumentation budget, three path values multiplied by four stage values and three outcome values permit 36 combinations. Those numbers describe a proposed schema, not provider behavior or measured traffic. Adding a unique attempt identifier as a metric label destroys that bound. A phone number or session token is worse: it creates a poor aggregation key while carrying sensitive authentication material into the monitoring system. Correlation identifiers, when necessary for a restricted diagnostic trace, should not become dashboard dimensions.

Retention is arithmetic.

For illustration, assume one million retained events per day at 200 bytes each. Seven days holds 1.4 billion bytes of event payload; 30 days holds six billion bytes, before indexes, replicas, or other storage overhead. These are hypothetical decimal-byte calculations, not a bill estimate. The useful design question is which investigation requires the additional history. Retaining aggregated placement counts longer than detailed attempt records can preserve the decision evidence while limiting how much authentication context accumulates. Set the retention policy deliberately, with the application's privacy and investigation requirements in view.

Sampling introduces another boundary. Sampled successful-attempt diagnostics can reduce event volume, but a sample is not the denominator for an exact completion rate. Keep aggregate counters independent of trace sampling. If detailed rejection records use a different sampling rate, document it; otherwise an analyst can mistake retention policy for a change in attacker behavior. Rejections need interpretation too. A rejected attempt is not proof that an attacker was stopped, just as a completed challenge is not proof that a legitimate customer reached a usable session.

Rejected option: challenge every returning customer

Universal login CAPTCHA was rejected for the default support journey because it imposes friction on every return to an existing conversation. It also makes the central question harder to answer: aggregate challenge completion becomes the dominant dashboard, while session outcomes and the people who leave before completion receive less attention. More recorded events do not repair that analytical gap.

There is a valid narrower use case. During an active automated-login attack, a temporary policy that challenges every login may be an appropriate containment measure alongside other authentication controls. Define the conditions for enabling and removing it, then compare login completion and rejection outcomes by placement. Treat the broader gate as a policy change requiring evidence. The standing decision remains selective challenges, separate widgets, and telemetry that measures the security-versus-friction trade-off without retaining every detail indefinitely.

References

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.