TL;DR

For a simple SMS 2FA login flow, keep a short-lived attempt record in your backend, let a verification service own the OTP secret, and authorize only after a successful code check. Poll your own attempt state for user experience, ingest delivery updates asynchronously, and handle a failed send with a bounded retry or a previously enrolled fallback factor.

Delivery status is evidence for operations. It is not proof of identity.

I use this design behind Node/Express applications even though the reference code below is Python: the framework route should be thin, and the security boundary belongs in a small service with explicit state transitions. I've spent too many on-call shifts separating carrier behavior from application behavior to let a browser, callback, or sent flag decide a login.

How should a simple backend SMS 2FA login flow poll delivery status and handle failed OTP sends?