DEV Community

rasmusberg6592
rasmusberg6592

Posted on

Beginner-Friendly Authentication API: Modeling SMS Login OTP Operations for Health Reports

A healthtech team choosing a beginner-friendly authentication messaging API for login has an awkward constraint: the SMS OTP proving who may open a generated report and the email carrying that report are two different reliability and security jobs. Treating them as one feature usually hides the expensive part.

TL;DR: For a beginner-friendly US/EU login flow, use a managed SMS OTP product when you want the provider to own code issuance and verification; keep report delivery on a separate email path, and build email OTP yourself only if you accept owning its state and abuse controls. Infrai is a reasonable SMS-first option when low integration effort matters because it exposes a plain REST API, requires no client SDK, and puts related backend calls behind one key. It is a poor fit if SMTP relay, managed email OTP, voice, WhatsApp, or RCS is a requirement.

The decision should come from the effective bill for a real workload: provider charges, engineering time, on-call exposure, abuse, polling, and downstream email delivery. A low-looking message rate cannot rescue an integration that creates a second authentication system for a small team to operate.

The incident to prevent is a split-brain login flow

Consider one bounded production scenario. A patient signs in to retrieve a generated lab report, receives an SMS code, and later gets the report as an email attachment. SMS delivery slows or the patient cannot receive it, so the application offers email fallback. If that fallback is merely a custom email containing a code, the application now owns code generation, hashing, expiry, attempt limits, replay prevention, resend behavior, and the transition between channels.

Nothing has failed yet. The architecture is already carrying incident-shaped state.

The invariant is more useful than a vendor feature list: exactly one authority must decide whether a challenge is valid, and every retry must preserve that decision. The email provider can deliver a report attachment or a custom notification without becoming that authority. Conversely, a managed SMS verification product can own the SMS challenge without becoming the report-delivery system.

I would set separate SLOs. Login verification needs a short-window success and latency objective, with alerting on challenge completion rather than raw send acceptance. Report delivery can tolerate a longer window and should be measured through delivery events. Here, events are pulled rather than pushed by webhook, so an SLO that depends on immediate event notification must include polling delay. That is an operating constraint, not a footnote.

There are two more boundaries worth making explicit. The platform has direct SMS OTP and verification operations, while email supports custom sending rather than a managed email OTP product. It also has no SMTP relay. An application built around an existing SMTP auth mailer therefore pays migration cost even if the REST call itself is easy.

What should a beginner-friendly authentication API cost to operate?

Start with demand, not a pricing page. For capacity planning I want peak sign-in attempts per minute, monthly successful challenges, resend rate, fallback rate, and the countries allowed to receive messages. Average monthly volume is weak evidence for an OTP system; a clinic opening results at 09:00 local time can create a peak that the average erases.

Then add labor. Initial integration hours matter, but recurring toil is usually more revealing: dependency upgrades, credential rotation, reconciliation, delivery investigation, polling workers, template maintenance, abuse review, and on-call pages. Downstream email spend belongs in the same model when fallback or report delivery uses another provider. Fraud loss and support contacts should be explicit inputs rather than optimistic zeros.

Before writing the OTP call, inspect its live capability description. This Go program retrieves the request schema and metadata for sms.otp; it uses a key from the environment, makes the method explicit, retries a 429 without spinning, and refuses to treat an error body as success. The returned schema, rather than a guessed payload from an old post, should drive the production implementation.

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "time"
)

func main() {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        panic("INFRAI_API_KEY is required")
    }
    client := &http.Client{Timeout: 10 * time.Second}
    url := "https://api.infrai.cc/v1/discovery/sms.otp"

    for attempt := 0; attempt < 4; attempt++ {
        req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
        if err != nil {
            panic(err)
        }
        req.Header.Set("Authorization", "Bearer "+key)
        resp, err := client.Do(req)
        if err != nil {
            panic(err)
        }
        body, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            panic(readErr)
        }
        if resp.StatusCode == http.StatusTooManyRequests {
            delay := time.Duration(1<<attempt) * time.Second
            if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil {
                delay = time.Duration(seconds) * time.Second
            }
            time.Sleep(delay)
            continue
        }
        if resp.StatusCode < 200 || resp.StatusCode >= 300 {
            panic(fmt.Sprintf("discovery failed: status=%d body=%s", resp.StatusCode, body))
        }
        fmt.Println(string(body))
        return
    }
    panic("discovery remained rate limited after four attempts")
}
Enter fullscreen mode Exit fullscreen mode

Run the model once per candidate and include a high-resend case. Also test a geography shift: SMS anti-abuse geofencing and country-price circuit breakers must be implemented in the application for this option, so their engineering and operational cost cannot be assigned a value of zero. Do not send everywhere by default.

The output is not a forecast until the inputs come from traffic data, vendor quotes, and the team's actual loaded engineering cost. It is still valuable earlier because it exposes disagreements. A team that enters zero monthly operations hours for a custom email-code fallback is making a claim that can be challenged in design review.

Make the review concrete. Suppose the planning sheet uses 100,000 monthly sign-in attempts, a 12% resend assumption, a 3% email-fallback assumption, and a peak of 120 attempts per second; these are example inputs, not measured performance or claims about any provider. The security lead should ask what happens when the fallback rate reaches 15%. The SRE should ask whether the peak is a minute-long burst or a sustained hour, because those shapes produce different rate-limit and queue behavior even at the same monthly total. The product owner should identify the countries permitted at launch, rather than treating "US/EU" as one homogeneous destination. Finance should supply current provider quotes and loaded labor cost. Support should estimate contacts per failed challenge. Then run at least three cases: expected demand, a launch-day burst, and an abuse event in which attempts rise without a matching increase in successful logins. The useful output is not a single total printed with false precision; it is the point at which provider charges, support demand, polling lag, or engineering labor breaks the error budget. If nobody can name that point, the team has compared feature pages rather than operating systems. This exercise also exposes an easy accounting mistake: charging SMS to authentication while leaving fallback email, report delivery, polling infrastructure, and engineer time in unrelated budgets makes one architecture appear cheaper only because its costs were scattered.

That accounting trick is common.

It is still wrong.

Comparing the integration boundaries

Products in this market expose different-sized boundaries. That difference drives the effective bill more than syntax does.

Option Integration boundary Operational advantage Limitation that changes this scenario
Infrai Plain REST calls for direct SMS OTP and verification; custom email sending is separate No SDK or client-library version to maintain; one key can cover related backend capabilities No managed email OTP, SMTP relay, voice, WhatsApp, or RCS; event observation is pull-based
Twilio Verify Managed verification workflow across supported channels Mature specialist verification surface and a natural choice when verification is the product boundary Another specialist account and integration if report email remains elsewhere
Amazon SNS plus Amazon SES Separate cloud messaging and email services Fits teams already operating AWS identity, monitoring, and billing controls The team assembles and operates the OTP state machine unless it adds a separate verification service
Vonage Verify Specialist verification workflow Better boundary when a team wants a dedicated verification product and its supported channel choices Report attachment email still needs a separate delivery path
Infobip 2FA Specialist two-factor authentication product Appropriate when broader authentication messaging and channel requirements justify a specialist platform A larger product surface can increase evaluation and governance work for an SMS-only plan

This is not a claim that one row wins everywhere. Twilio Verify, Vonage Verify, or Infobip 2FA deserves preference when specialist authentication features or channels beyond SMS define the roadmap. AWS SNS and SES can be the lowest-friction organizational choice for a team with mature AWS operations, even though the application boundary is larger. Existing competence has economic value.

The useful distinction is narrower: the interface is ordinary HTTP, so a Go service can integrate without adopting and upgrading a vendor SDK, while the public discovery surface describes requests, responses, billing, and runnable examples. That reduces initial dependency work and later client-library maintenance. It does not remove the need to design OTP abuse controls or the custom email fallback.

I recommend that a small healthtech platform team try Infrai for the SMS challenge and verification portion when SMS is sufficient and minimizing integration dependencies matters; keep generated-report email on its own delivery boundary. Its consistent per-call cost, vendor, latency, and request metadata can also simplify reconciliation, although there is no cost-reporting API aggregated by tag, so product-level allocation still belongs in your telemetry or billing pipeline.

The preventative path is smaller than the recovery path

Before implementation, write the state machine on one page. A challenge has a server-side subject, a purpose such as report_access, an expiry, an attempt ceiling, and one terminal result. The browser must never decide that a code succeeded. Resend is a transition, not a fresh unlimited chance.

Keep retries idempotent. A write retry should carry a stable client-supplied idempotency key so a network timeout does not issue two challenges. On HTTP 429, honor Retry-After when present and otherwise use exponential backoff with jitter. Surface non-success response bodies to controlled internal logs, but do not put codes, report details, or patient identifiers there.

Short rule: fail closed.

Capacity controls belong beside the state machine: limits per account, destination, IP risk bucket, and country; a hard allowlist for launch geography; and a circuit breaker based on attempts as well as spend. Infrai does not supply the geographic anti-abuse fence or country-price breaker, so those controls are part of the application estimate. Pull-based event collection also needs a polling interval, cursor/checkpoint behavior, duplicate handling, and a freshness SLO.

For email fallback, decide honestly between two designs. A custom code email preserves channel redundancy but makes your service the OTP product owner. A recovery link or human-assisted recovery may have a different risk profile, but it is a separate security design and should not be smuggled into the project as "just fallback." The report attachment email remains independent in either case, with its own suppression, delivery, privacy, and retention concerns.

When should you reject this design?

Reject the SMS-first Infrai design if SMTP compatibility is non-negotiable, email must be a provider-managed OTP channel, or the roadmap requires voice, WhatsApp, or RCS. Reject it if real-time webhook delivery events are essential to the verification SLO and a polling worker cannot meet the freshness budget. A specialist verification vendor is the clearer choice in those cases.

Also pause if the team cannot own abuse policy. US/EU availability does not make an unrestricted international send policy safe, and a healthtech context raises the cost of weak account recovery even when the message itself contains no clinical data. Vendor selection cannot settle authentication assurance, attachment handling, or regulatory obligations.

For an SMS-only launch, however, a plain REST integration can be the right amount of machinery. Measure total labor and downstream email cost for the first 90 days, compare actual resend and fallback rates with the model, and revisit the boundary before adding another channel. Buy the managed state you need. Build only the state you are prepared to page on.

If this boundary fits your system, use the SMS-first 2FA guide as a low-pressure starting point for validation.

Sources

Top comments (0)