Two-factor authentication

In preview

Add a second factor in two calls.

Set up in:
Cursor

Two-factor authentication adds a second proof on top of a password: a one-time code on a channel the user controls. With Bird Verify it's a send call at the moment of login and a check call when the user types the code back — SMS, WhatsApp, or email today, per-country channel config, and nothing to store between the two.

verify.ts
200 · pending
import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });

// Send the code, then check it by recipient.
await bird.verify.verifications.create({
  to: { phone_number: "+15551234567" },
}).safe();

const { data } = await bird.verify.verifications.check({
  to:   { phone_number: "+15551234567" },
  code: userInput,
}).safe();

2FA is the verification flow, pointed at login.

Under the hood, 2FA is the same flow the Bird Verify API runs everywhere: create a verification for the user's phone or email when they sign in, then check the code they enter. Because the check is by recipient, your login handler keeps no per-attempt state, and the channel a given user gets is decided by your per-country configuration, not hard-coded in the flow. Drop the password in front of it and the same flow becomes passwordless login.

What you wire up for 2FA.

Two calls and a configuration.

  1. 01

    Send on login, check on submit.

    Create a verification when the user authenticates with their first factor; check the code when they enter it. That's the whole integration.

  2. 02

    SMS, WhatsApp, or email as the factor.

    Use the channel you already have for the user: a phone number over SMS or WhatsApp, an email over email. Voice is rolling out for more options.

  3. 03

    Per-app configuration.

    Keep a separate configuration for login versus signup versus high-value actions, each with its own code rules and channel plan.

  4. 04

    Brute force is bounded.

    Attempt lockout and per-recipient send caps come built in, so a second factor doesn't become a new attack surface.

The login-time flow.

Send the code once the password checks out; verify it when the user submits. A wrong code is a result you branch on, not an exception to catch.

two-factor.ts
200
// Send the second factor once the password checks out.
await bird.verify.verifications.create({
  to: { phone_number: user.phone },
}).safe();

const { data } = await bird.verify.verifications.check({
  to:   { phone_number: user.phone },
  code: submitted,
}).safe();

if (data.result) grantSession(user);

2FA FAQ

What's the difference between 2FA and MFA?+
Two-factor authentication uses exactly two factors — typically a password plus a one-time code. Multi-factor authentication is the general term for two or more. Bird Verify provides the code-based factor for either.
Which channel should I use for the second factor?+
Use the address you already have: a phone number verifies over SMS or WhatsApp, an email address over email. Per-country configuration controls the order and senders per market.
Does adding 2FA mean storing verification state?+
No. Bird checks by recipient, so your login handler sends the code and later checks it by the same address — there's no verification id or pending-code record to keep on your side.
Who do my users see the code from?+
Authifly, Bird's verification brand. It's the identity on every code your users receive: email arrives from otp@verify.authifly.com or your own verified domain, and SMS and WhatsApp are Authifly-branded. authifly.com is a public page that reassures recipients Authifly sends legitimate one-time codes on a business's behalf. Bird is the platform you build on; Authifly is what the recipient sees.

Two-factor authentication, on the same API as your other channels.

Bird Verify is the code-based factor for your login and signup — SMS, email, and WhatsApp now, voice rolling out.

Start with one channel.
Add the others when you're ready.

A test API key is yours immediately. Production unlocks when you add a payment method and verify a sender.

Using Claude Code, Cursor, or Codex? Copy a setup prompt and your agent installs the Bird CLI and skills for you. Pick yours:

Cursor