Two-Factor Authentication via SMS

Add SMS 2FA to Your App
in Under an Hour

Protect user accounts with one-time codes sent via SMS. Works on every mobile phone worldwide — no authenticator app required. Simple REST API with code examples in every language.

How SMS 2FA Works

1

User logs in

User enters their password correctly on your login page.

2

You call SMSPM

Your server generates a 6-digit code and calls the SMSPM API to send it.

3

Code delivered

User receives the code on their phone and enters it. Your server verifies and grants access.

Complete 2FA Implementation

Below is a production-ready 2FA SMS flow in Node.js. The same pattern works in Python, PHP, or any language — see the full OTP guide for multi-language examples.

01
Generate code — Use crypto.randomInt() — not Math.random()
02
Store server-side — Redis with 10-minute TTL, max 3 attempts
03
Send via SMSPM — Single API call, gets message ID back
04
Verify on submit — Check code, expiry, and attempt count
05
Consume code — Delete from Redis after successful verify
Node.js — 2fa.js
import { randomInt } from 'crypto';

// STEP 1 — Initiate 2FA after password check
export async function initiate2FA(userId, phone) {
  const code = String(randomInt(100000, 999999));
  
  // STEP 2 — Store with TTL and attempt counter
  await redis.set(
    `2fa:${userId}`,
    JSON.stringify({ code, attempts: 0 }),
    { EX: 600 }  // 10 minutes
  );

  // STEP 3 — Send via SMSPM
  const params = new URLSearchParams({
    hash: process.env.SMSPM_HASH,
    token: process.env.SMSPM_TOKEN,
    toNumber: phone,
    fromNumber: 'MyApp',
    text: `Your MyApp login code: ${code}. Valid 10 min.`
  });
  await fetch(`https://api.smspm.com?${params}`);
}

// STEP 4+5 — Verify the submitted code
export async function verify2FA(userId, submitted) {
  const raw = await redis.get(`2fa:${userId}`);
  if (!raw) return { ok: false, reason: 'expired' };
  
  const record = JSON.parse(raw);
  if (record.attempts >= 3)
    return { ok: false, reason: 'too_many_attempts' };
  
  if (submitted !== record.code) {
    record.attempts++;
    await redis.set(`2fa:${userId}`,
      JSON.stringify(record), { EX: 600 });
    return { ok: false, reason: 'wrong_code' };
  }
  
  await redis.del(`2fa:${userId}`); // consume
  return { ok: true };
}

SMS 2FA vs Other Second Factors

We'll be honest: SMS 2FA isn't the most secure option if SIM-swap attacks are a realistic threat for your users. But for most consumer apps, the combination of wide reach, zero user friction, and straightforward implementation makes it the right first choice.

Method No app needed Global reach User friction Cost / user Dev setup
SMS 2FA Low ~€0.04/user Hours
TOTP (Authenticator app) Medium Free Days
Email OTP Medium Low Hours
Hardware token High €5–30/token Weeks

For high-security use cases (banking, crypto), consider adding TOTP as an option alongside SMS 2FA.

The SIM-Swap Risk: When to Offer TOTP Instead

SMS 2FA works for most use cases, but certain accounts warrant stronger protection.

⚠️ What is SIM Swapping?

A SIM-swap attack (SIM jacking) occurs when an attacker convinces your telecom carrier to port your phone number to a SIM card they control. They gain access to your account password, but when 2FA SMS is sent, they intercept it since they now control your phone number.

How it happens: Attacker calls your carrier, social-engineers support staff (using public info like address or last 4 digits of SSN), and requests a SIM replacement. Boom — they own your SMS inbox.

🎯 Who's at Risk?

  • Crypto / DeFi users (high-value accounts, attacker motivation)
  • High-profile accounts (celebrities, influencers, public figures)
  • Enterprise accounts (C-suite, finance teams with access to large assets)
  • Email recovery accounts (if your main email uses SMS 2FA, and attacker resets your password)
  • Typical consumer apps (Netflix, Spotify, Pinterest — low attacker motivation)

✅ Best Practice: Offer Multiple 2FA Options

Default to SMS 2FA:

  • • Works on every phone (no app download required)
  • • Highest adoption rate (90%+)
  • • Perfect for first-time setup
  • • Balances security + usability

Offer TOTP as Optional Upgrade:

  • • For users who want extra security
  • • Not vulnerable to SIM-swap attacks
  • • (Requires Google Authenticator or Authy)
  • • Let power users choose both (defense-in-depth)
🛡️

If Your Users Are High-Risk:

Make TOTP mandatory for sensitive actions (fund transfers, password changes). Allow SMS as a backup. Warn users about SIM-swap risk during 2FA setup.

📱

If Your Users Are Average Consumers:

SMS 2FA is the right choice. It's convenient, works globally, and the SIM-swap risk is negligible for your user base. Offer TOTP as an optional paranoia upgrade for those who want it.

Security Best Practices

Rate limit per phone number

Allow at most one code request per phone number per 60 seconds. Block IPs that request more than 5 codes per hour.

Short expiry

10 minutes maximum. For login 2FA, 5 minutes is better — a legitimate user will complete it quickly.

Max 3 attempts

After 3 wrong codes, invalidate the session and require a fresh code request. This prevents brute-force against 6-digit codes (1,000,000 possibilities).

Consume immediately

Delete the stored code from Redis/database immediately after a successful verify — never allow a code to be used twice.

Never log the code itself

Log the message ID and phone number for audit purposes, but never the OTP code value.

Ready to Add SMS 2FA?

Free account, test credits included. First OTP sending in under 15 minutes.