Two-factor authentication
In previewAdd a second factor in two calls.
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.
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.
- 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.
- 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.
- 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.
- 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.
// 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?+
Which channel should I use for the second factor?+
Does adding 2FA mean storing verification state?+
Who do my users see the code from?+
Build it on the Verify platform
The channels and controls behind your 2FA flow.
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.