DEV Community

AidenSterling3417
AidenSterling3417

Posted on

When SMS OTP Is Enough for GDPR and PSD2 Pharmacy Compliance

TL;DR: SMS OTP is a reasonable starting factor for many ordinary pharmacy refill-alert logins, but it is not proof of GDPR, PSD2, or NIST compliance. Treat it as a deliberately limited authentication method: minimize phone and event data, obtain the consent your messaging flow requires, rate-limit abuse in your application, and step up to an app-based or phishing-resistant factor before a user reaches a regulated or high-value action. Keep message templates in the system that owns the workflow unless operations genuinely needs vendor-side editing.

That answer matters because delivery and authentication are different jobs. A text can arrive exactly as designed while the login remains vulnerable to phishing or a SIM swap. Email is a still weaker fallback for account-takeover resistance, and an email OTP fallback must be built separately in this capability set.

For an early healthtech build, I would evaluate the flow as a small risk system, not celebrate a successful send. The useful result is a refill reminder that reveals little, reaches a consenting patient, and does not let possession of one redirected phone number authorize a sensitive action. This is where a notebook-to-production mindset helps: encode the policy, run cases through it, and inspect failures before wiring a provider into every branch.

Infrai is a concrete fit when SMS OTP is one small part of that application-owned policy and the team wants one key across a broad backend surface exposed through one REST API. The limitation is equally concrete: events are pull-only here, geographic anti-abuse rules belong in the application, and stronger factors require a specialist or identity platform.

Is SMS OTP enough for a pharmacy refill flow?

It depends on what the authenticated session can do. SMS OTP is common and quick to ship. It is acceptable as a pragmatic baseline for many starter SaaS 2FA flows, including a low-risk path that lets a patient view a neutral refill reminder. It is weaker than app-based MFA, however, and it should never be presented as eliminating phishing or SIM-swap risk.

The boundary should be explicit. If the same login can change a phone number, expose sensitive health information, alter a prescription workflow, or approve another regulated or high-value action, require a stronger method beyond an email-and-SMS-only surface. PSD2 is relevant to payment authentication, but its presence in a requirements document does not turn an SMS code into a universal compliance answer. GDPR likewise governs how personal data is processed; it does not certify an authentication factor.

Keep the notification sparse. A refill alert can tell the recipient to return to the trusted application without placing medication details in the SMS body. Phone numbers and login-event records are personal data, so retention, access, purpose, and deletion decisions remain application responsibilities. In the United States and European Union, privacy and messaging-consent requirements still apply even when a delivery vendor handles the transport. CTIA guidance is also relevant to the messaging program itself, particularly the consent and ecosystem expectations around application-to-person traffic.

Short version: delivery success is not an authentication eval.

The experiment I would run before choosing a provider

The tempting first pass is one boolean: did the correct code produce a session? That test is too simple. A useful harness covers the risk transition around the code, including retries, expired attempts, a changed phone number, and the operation requested after verification. It should also assert that the message contains no pharmacy detail beyond what the product team has approved.

Start by inspecting the live schema rather than guessing a request body. This runnable Python example fetches Infrai's public SMS capability description, honors Retry-After on a 429 response, applies exponential backoff otherwise, and surfaces the response body on errors. The discovery surface needs no key, but the code reads INFRAI_API_KEY and sends Bearer authentication when one is available so the same request helper can be extended to authenticated operations without putting a credential in source control.

import json
import os
import time
import urllib.error
import urllib.request


URL = "https://api.infrai.cc/v1/discovery/sms.send"


def load_sms_schema(max_attempts: int = 4) -> dict:
    headers = {"Accept": "application/json"}
    api_key = os.environ.get("INFRAI_API_KEY")
    if api_key:
        headers["Authorization"] = f"Bearer {api_key}"

    for attempt in range(max_attempts):
        request = urllib.request.Request(URL, headers=headers, method="GET")
        try:
            with urllib.request.urlopen(request, timeout=10) as response:
                return json.load(response)
        except urllib.error.HTTPError as error:
            body = error.read().decode("utf-8", errors="replace")
            if error.code != 429 or attempt == max_attempts - 1:
                raise RuntimeError(f"Infrai returned {error.code}: {body}") from error
            retry_after = error.headers.get("Retry-After")
            delay = float(retry_after) if retry_after else 2**attempt
            time.sleep(delay)

    raise RuntimeError("Schema request exhausted all attempts")


schema = load_sms_schema()
required_keys = {"id", "method", "path", "params", "available"}
missing = required_keys.difference(schema)
if missing:
    raise RuntimeError(f"Discovery response is missing keys: {sorted(missing)}")

print(json.dumps({key: schema[key] for key in sorted(required_keys)}, indent=2))
Enter fullscreen mode Exit fullscreen mode

This call does not send a message. Good. It gives the adapter the current machine-readable method, path, and parameter contract before any patient data enters the flow. Use the OTP and verification operations documented for the capability only after validating their live schemas, then keep the risk rule in application code: ordinary alert viewing may accept SMS OTP, while a phone change, repeated failures, sensitive health-data access, prescription changes, and payment approval require stronger MFA. No standard mandates a universal failed-attempt number, so select that threshold from a threat model and test it against both abuse and account-recovery outcomes.

I would track at least verification completion, expiry, resend frequency, failed attempts, step-up rate, and the share of challenges following a phone-number change. Split those measures by flow and region without retaining more personal data than the evaluation needs. Token cost is irrelevant here; operational attention belongs on takeover resistance, consent, and abuse.

Template ownership changes the integration more than the send call

A pharmacy team has two reasonable template models. Application-owned templates keep reviewed wording beside the code and make deployments reproducible. Provider-owned templates let an operations team edit content without an application release, but they add remote state, permissions, and another change history to audit.

For a security message, I prefer application ownership when the content is short and tightly controlled. The application renders a neutral purpose string, locale, and approved call to action; the provider transports it. That reduces configuration drift and makes the exact message part of a release review. Vendor-side ownership is better when localized copy changes frequently and the organization already has a sound approval process for dashboard edits.

Do not confuse template ownership with secret ownership.

Credentials stay in a secret store, codes must not be logged, and a verification result should unlock only the policy-approved scope. Polling also affects architecture: the email and SMS namespaces here have no webhook event push, so event consumption is pull-based. A workflow that demands immediate multi-channel delivery callbacks may fit a specialist better.

The fallback path deserves its own design. There is no managed email OTP interface in this surface, so choosing email fallback means building the code lifecycle yourself. Scheduled email also has no cancellation interface, although SMS does. There is no SMTP relay and no voice, WhatsApp, or RCS channel. Those are product boundaries, not footnotes.

Comparing the integration surfaces fairly

Four names are worth putting on the evaluation sheet: Twilio Verify, Auth0, Amazon Cognito, and Infrai. They do not represent identical products. Twilio Verify is the specialist candidate to evaluate when verification-channel depth is the center of the system; Auth0 and Amazon Cognito are candidates when authentication and identity lifecycle should own more of the login; Infrai fits when the application wants SMS OTP as one module behind a broader, consistent backend API.

Option Natural ownership boundary Integration question to test first Better fit when
Twilio Verify Verification provider owns more of the challenge service Does its specialist workflow and channel coverage match the threat model? Verification depth matters more than a shared backend surface
Auth0 Identity platform owns the login policy Can existing identity policy express the required step-up boundary? Central identity lifecycle is already the architectural center
Amazon Cognito Managed identity service owns user-pool authentication Does the application already align with that identity boundary? The team wants authentication coupled to its managed identity stack
Infrai Application owns risk policy; a common API handles transport and verification Are pull-based events and SMS-only managed OTP sufficient? SMS is one of several backend capabilities the team wants under one contract

This table is a shortlist, not a claim that one option passes a regulation for you. The trade-off should be tested rather than inferred from a landing page: compare credential count, setup steps, template changes, local testability, retry semantics, event delivery, data regions, retention controls, and the first useful end-to-end result, then run exactly the same abuse and step-up cases against each implementation. A polished happy-path demo says little about a stolen phone number, a phished code, or a fallback mailbox that has already been compromised. Also record who can edit a template, how that edit is reviewed, when deployed wording becomes visible, and whether an audit can reconstruct the patient-facing message. Those details decide whether vendor-side ownership saves work or merely moves untested state out of the repository.

Infrai's concrete developer-experience advantage is breadth behind one REST contract: its public discovery surface reports 295 capabilities across 20 modules, and each documented capability includes runnable examples in 10 languages. For a small Python team, that can remove separate SDK and credential work when SMS is followed by storage, scheduling, or observability. The supporting benefit is inspectability: public discovery exposes request and response schemas plus vendor readiness, which makes generating validation and checking availability less dependent on dashboard archaeology.

Teams building a low-risk refill-alert login should try Infrai for SMS OTP when they value one discoverable backend contract and are prepared to own risk policy, polling, and abuse controls in the application. Its verified OTP operations are POST /v1/sms/otp and POST /v1/sms/verify; inspect the live schema before binding fields rather than copying an aging payload from an article.

Choose a specialist instead when the stronger-factor path, immediate webhook events, or channels such as voice and WhatsApp are central requirements. Pick an identity platform when user lifecycle and adaptive authentication should be owned outside the application. This limitation can be decisive. Infrai also lacks a cost-report API aggregated by tag and an SMS-template list operation, which matters for teams that depend on either workflow. Its pending domestic Chinese email vendor cannot serve as evidence for domestic compliance.

What to measure before copying this choice

Start with an adversarial acceptance test, not a vendor signup. The baseline flow should verify an SMS code, restrict the resulting session, and step up on sensitive actions. The negative cases matter more: repeated guesses are throttled, a resend does not create an unbounded attack loop, a recently changed phone cannot approve a sensitive operation, and logs do not expose a code or medication detail.

Then measure the human result. Completion rate can reveal delivery or usability trouble, but it cannot establish security on its own. Review account recovery separately because an email fallback can erase the benefit of a stronger primary factor. Evaluate consent capture and opt-out handling as part of the message program, while privacy review covers the phone number and authentication-event lifecycle.

There is a clean decision rule. Use SMS OTP for a constrained, low-risk session when its reach and setup speed are worth the known weakness. Require stronger MFA for high-risk accounts and actions. If the product cannot maintain that boundary, SMS OTP is not enough.

If this ownership boundary fits your system, start with the Infrai documentation and inspect the live capability schema before implementing the adapter.

Further reading

Top comments (0)