A password alone, no matter how strong, is a single point of failure — if it leaks through a breach on another site, a phishing page, or a keylogger, an attacker has everything they need to log in as that user. Two-factor authentication adds a second, independent proof of identity, typically a time-based code from an app on the user's phone, so a leaked password alone is no longer enough to take over an account.
How Time-Based One-Time Passwords Work
TOTP (Time-based One-Time Password) generates a short numeric code from a shared secret and the current time, recalculated every 30 seconds on both the server and the user's authenticator app independently. Because both sides compute the same code from the same secret and roughly the same timestamp, no network communication is needed between the app and your server at verification time, which is why TOTP works even when a phone has no internet connection.
composer require pragmarx/google2fa
use PragmaRXGoogle2FAGoogle2FA;
$google2fa = new Google2FA();
$secret = $google2fa->generateSecretKey();
// store $secret encrypted against the user recordGenerating a QR Code for Easy Setup
Asking a user to manually type a long secret key into their authenticator app is error-prone and frustrating. Generating a QR code encoding the secret, account name, and issuer lets the user simply scan it with their phone's camera, which is the setup experience virtually every authenticator app expects and users are already familiar with.
$qrCodeUrl = $google2fa->getQRCodeUrl(
config('app.name'),
$user->email,
$secret
);Verifying Submitted Codes
When the user submits a code, either during setup confirmation or at every subsequent login, the server recomputes the expected code from the stored secret and compares it against what was submitted, allowing for a small window of clock drift since phone and server clocks are rarely perfectly synchronized.
$valid = $google2fa->verifyKey($user->two_factor_secret, $request->input('code'));
if (!$valid) {
return back()->withErrors(['code' => 'Invalid authentication code.']);
}Recovery Codes for When a Device Is Lost
A user who loses their phone, with no backup, would otherwise be permanently locked out of their own account once 2FA is enabled. Generating a set of single-use recovery codes at setup time, shown once and meant to be stored somewhere safe, gives a legitimate path back into the account without undermining the protection 2FA provides against everyone else.
What Happens If the Secret Itself Leaks
The TOTP secret, unlike a password, is rarely something a user types anywhere after initial setup, but it must still be protected with the same seriousness as a password, since anyone who obtains it can generate valid codes indefinitely without ever needing the user's phone. Storing the secret encrypted at rest, not in plain text, is the baseline expectation; a database breach exposing plain-text 2FA secrets defeats the entire protection 2FA was meant to add.
Enforcing 2FA for Sensitive Roles
Making 2FA optional for every user is reasonable for a general consumer application, but accounts with elevated privileges (admins, billing access, anyone who can change other users' permissions) represent disproportionate risk if compromised. Requiring 2FA specifically for these roles, even while leaving it optional elsewhere, concentrates the protection where a compromise would do the most damage.
SMS-Based 2FA and Why TOTP Is Preferred
SMS-delivered codes were an early, common form of 2FA, but SIM-swapping attacks — where an attacker convinces a carrier to transfer a victim's phone number to a new SIM card — have made SMS a meaningfully weaker second factor than an authenticator app, since the underlying telecom infrastructure was never designed with this security use case in mind. TOTP apps, generating codes locally without any network dependency, avoid this entire class of attack and are now the generally recommended default over SMS.
Remember-This-Device Functionality
Requiring a 2FA code on every single login, even from a device the user logs in from daily, creates friction many users find excessive. A "remember this device" option, setting a long-lived signed cookie that skips the 2FA prompt on subsequent logins from that specific device, balances security and convenience, provided the cookie itself is properly signed and scoped so it cannot be forged or replayed from a different device.
Case Study: The Account Takeover That 2FA Would Have Stopped
A SaaS company suffered a wave of account takeovers after a third-party data breach exposed a large set of email/password combinations, several of which were reused by their own users. Attackers used these leaked credentials in automated credential-stuffing attacks, successfully logging into dozens of accounts that had never been individually targeted or phished — the password alone was sufficient, since no second factor existed. After the incident, the company made 2FA mandatory for all accounts and saw credential-stuffing login attempts drop to functionally zero successful takeovers, since a leaked password alone was no longer enough.
A Glossary for This Topic
TOTP — Time-based One-Time Password, a code generated from a shared secret and the current time. Authenticator app — a mobile app generating TOTP codes locally (Google Authenticator, Authy). Recovery code — a single-use backup code allowing account access if the primary 2FA device is lost. Credential stuffing — using leaked username/password pairs from one breach to attempt logins on unrelated services. SIM swapping — an attack transferring a victim's phone number to an attacker-controlled SIM.
Frequently Asked Questions
Does 2FA make my application immune to account takeover? No, but it removes the single point of failure a password represents, closing off by far the most common takeover vector. Should 2FA be mandatory for all users? It depends on your application's risk profile; mandatory for sensitive roles and optional elsewhere is a reasonable middle ground for many applications. What happens if a user loses both their phone and their recovery codes? You need a manual identity-verification recovery process as a last resort, since there is no way to algorithmically restore access otherwise.
Step-by-Step: Adding 2FA to an Existing Login System
Install a TOTP library (pragmarx/google2fa for Laravel) and add a two_factor_secret and two_factor_enabled column to the users table. Build a setup page generating a secret and QR code, requiring the user to enter a valid generated code before enabling 2FA (confirming the app was scanned correctly, not just displayed). Add a 2FA challenge step to the login flow, shown only after correct password verification, for any user with 2FA enabled. Generate and display a set of recovery codes at setup time, storing them hashed. Add a "remember this device" option to reduce repeated friction.
A Comparison Table: 2FA Methods
SMS codes: low setup friction, vulnerable to SIM swapping, not recommended as primary. TOTP apps: no network dependency, requires installing an app, strong protection, the common recommended default. Hardware security keys (FIDO2/WebAuthn): strongest protection against phishing, requires a physical device, best for high-value accounts. Push notifications: convenient, requires the provider's own app installed, good UX-security balance.
Security Considerations Checklist
Never allow 2FA setup confirmation to succeed without verifying an actual generated code, since skipping this step risks a user mistyping the secret into their app and being silently locked out later without realizing setup never actually worked. Rate-limit 2FA code submission attempts, since a 6-digit TOTP code has a limited keyspace that becomes brute-forceable without throttling. Store recovery codes hashed, the same as passwords, never in plain text.
Accessibility Considerations
A QR code for 2FA setup is inherently a visual-only element; always provide the underlying secret as selectable, readable text alongside it, since some authenticator apps and assistive-technology users need to enter it manually rather than scanning.
How This Plays Out at Different Scales
A small application can offer 2FA as a simple opt-in with TOTP only. A growing application with sensitive user data should make 2FA mandatory for elevated roles and strongly encouraged elsewhere. A large platform handling significant financial or personal data typically needs to support hardware security keys (WebAuthn) alongside TOTP for users who want the strongest available protection.
What to Do When You Inherit an Application With No 2FA at All
Inheriting an application with thousands of existing users and no 2FA support is a common starting point, and retrofitting it requires care not to lock anyone out unexpectedly. Roll out 2FA as fully optional first, build the setup and verification flow, then gradually move toward requiring it for elevated roles once the flow has been tested in production with real users, rather than flipping a mandatory switch for everyone on day one.
Final Checklist Before Calling 2FA Production Ready
TOTP secrets are encrypted at rest, never stored in plain text. Code submission is rate-limited to prevent brute-forcing the 6-digit keyspace. Recovery codes are generated, shown once, and stored hashed. A manual recovery process exists for users who lose both their device and recovery codes. 2FA is enforced for admin and other elevated-privilege roles.
Closing Thought, Revisited
Two-factor authentication is one of the highest-value security investments available relative to its implementation cost — a relatively small amount of code closing off the single most common account-takeover vector. The case study above is the standard argument for it: a password leaked anywhere, even from a service you have nothing to do with, should not be enough on its own to take over an account on yours.
2FA and API Access Tokens
A user with 2FA enabled for browser-based login still needs a separate mechanism for API access (a personal access token, an OAuth client), since a TOTP challenge has no natural place in a non-interactive API call. Scoping API tokens narrowly and letting users revoke them individually gives equivalent protection for programmatic access without forcing an awkward 2FA prompt into a context it was never designed for.
Biometric Authentication as a Complementary Factor
Mobile-app-based authentication increasingly layers biometric verification (fingerprint, face recognition) on top of or instead of a typed code, using the device's own secure hardware to protect the underlying credential. This is a convenience improvement over typing a 6-digit code more than a fundamentally different security model, since the biometric check still ultimately unlocks the same TOTP secret or equivalent credential stored on the device.
Notifying Users of New Device Logins
Even with 2FA enabled, notifying a user by email whenever their account is accessed from a new, previously unseen device or location gives them visibility into activity they did not initiate, letting them respond quickly (changing a password, revoking sessions) to a successful but unexpected login rather than discovering a compromise much later. This complements 2FA rather than replacing it, since 2FA prevents the takeover while device notifications help catch the rare case where it was somehow bypassed.
Session Invalidation After 2FA Changes
Disabling 2FA, changing the secret, or regenerating recovery codes should invalidate any existing active sessions other than the one making the change, since these actions typically follow a security concern and any other still-active session could belong to whoever caused that concern in the first place.
2FA Enrollment Rates and Encouraging Adoption
Optional 2FA tends to see fairly low voluntary enrollment unless actively encouraged — a one-time prompt after signup, a small account-security score showing 2FA as an easy improvement, or a brief incentive can meaningfully increase adoption compared to a feature that exists but is never surfaced to users who would benefit from it but simply never think to look for it in account settings.
2FA During Account Recovery Flows
A password-reset flow that successfully bypasses 2FA entirely once a user proves email ownership undermines much of the protection 2FA provides, since email accounts are themselves a common compromise target. Requiring 2FA verification (or a recovery code) as part of password reset, not just email confirmation, keeps the second factor meaningful even during account-recovery scenarios where it would otherwise be quietly skipped.