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.