Product Decisions This Supports
- Build vs. buy for MFA (TOTP): This package is the "buy" answer for the cryptographic core. RFC 4226 (HOTP) and RFC 6238 (TOTP) are fully specified, well-audited commodity algorithms. Writing your own HOTP/TOTP implementation is a security liability with zero product differentiation — the decision here is "commodity dependency, not custom code," and this package is a direct expression of that.
- Scope boundary for an MFA feature: The critical roadmap insight is what this package does not do. It ships the secret generation, QR provisioning URL, and key verification — and explicitly defers QR rendering (separate package), Laravel integration (separate bridge), and says nothing about recovery codes, enrollment state, rate limiting, or lockout UX. So the feature estimate is not "add a Composer dependency"; it's "dependency + 2 companion packages + product surface we still own." That reframes the epic's size for planning.
- Secret length / schema decisions (v9 breaking change): v9.0.0 moved the default secret from 16 to 32 characters (80 → 160 bits of entropy). This is a concrete, ticketable migration: audit the
google2fa_secret column width, any length validation rules, test fixtures asserting 16 chars, and the enrollment UI layout. It's also a one-way-door decision for new schemas — size the column for 32 now even if you generate 16.
- Security vs. UX tuning as an explicit product dial: The validation
$window parameter (default ±1 interval, ±30s) directly controls both clock-skew tolerance and the real-world validity period users experience. A window of 1 makes a 30-second code effectively valid for ~60 seconds; a window of 0 will reject codes from users who typed slowly. This is a support-ticket driver and should be set deliberately, not left at default by accident.
- Replay protection as a data-model requirement:
verifyKeyNewer() requires persisting the last-used key timestamp per user. That's a schema addition and a state-management decision most teams miss on the first pass — worth scoping up front if the threat model includes shoulder-surfing/credential replay.
- Compliance and enterprise-readiness roadmap: MFA on admin and privileged accounts is a standard control ask in SOC 2 / ISO 27001 customer questionnaires. Adopting a vetted, RFC-compliant library lets you answer "yes" on a security review far faster than a homegrown implementation, and supports the "we require MFA for admin access" commitment in sales conversations.
- Upgrade cadence as ongoing product cost: The maintainer publishes an explicit support policy (9.x active, 8.x maintenance-only, 7.x and older unsupported, tracking PHP's own support window). That's a predictable, budgetable maintenance line item — pin the major version and schedule an upgrade review each PHP release cycle rather than discovering it during a security audit.
- Operational dependency on server time sync: TOTP correctness depends on NTP-synced servers, which the README calls out directly. This is an infrastructure requirement that must be validated in your deploy/runbook process, because failures surface as user-facing "my code doesn't work" tickets with no obvious product cause.
Data-quality caveat: the provided repository metrics (1 star, 0 dependents) conflict with the package's observable ecosystem footprint — it's the long-standing TOTP implementation in the Laravel community, with a dedicated Laravel bridge and QR companion package. Treat those numbers as unreliable before citing them in any stakeholder deck; verify live Packagist download and dependent counts first.
When to Consider This Package
Adopt when:
- You're on PHP (7.4–8.4 supported per the compatibility table) and want standard authenticator-app TOTP — Google Authenticator, Authy, 1Password, etc.
- Your primary need is MFA for internal/admin/privileged users, where the audience tolerates an authenticator app and you want the smallest possible dependency surface.
- You're prepared to own the surrounding product work: enrollment flow, QR rendering (via BaconQrCode or the maintained QR companion package), recovery codes, rate limiting, and support documentation.
- You want an MIT-licensed, vendor-neutral primitive with no per-authentication pricing and no third-party identity data leaving your infrastructure.
- You need HOTP as well as TOTP, or non-default HMAC algorithms (SHA1/SHA256/SHA512) for a specific integration.
Look elsewhere when:
- Passkeys/WebAuthn, SMS, email OTP, or push are on the near-term roadmap. This package does none of them; a managed IdP (Okta, Auth0, WorkOS, Cognito) or a broader MFA library avoids a second migration six months later.
- You want recovery flows and lockout UX out of the box. Neither is in scope here, and recovery-code design is where homegrown MFA projects most often fail audits.
- You're building for a consumer audience with low tolerance for setup friction — authenticator apps have measurable enrollment drop-off versus SMS/email, and the tooling choice doesn't fix that.
- You need a managed service with SLAs, uptime guarantees, or vendor support. This is a solo-maintained open-source component; the support contract is the MIT license.
- Your stack isn't PHP — the algorithm is portable, but this specific package isn't.
- You require FIDO2/attestation for regulatory reasons (some financial and government contexts); TOTP alone won't satisfy that.
Also note two documentation inconsistencies to resolve in your spike before committing: the Requirements section says PHP 7.1+, while the compatibility table starts at 7.4; and the v9 migration guide's "old default behavior" code snippet is a copy-paste artifact. Neither is blocking, but both suggest you should validate the exact behavior in a branch rather than trusting the docs verbatim.
How to Pitch It (Stakeholders)
To executives (one paragraph): We can deliver authenticator-app two-factor authentication without building cryptography ourselves, using a small, MIT-licensed, standards-compliant PHP library. It's free, it keeps user secrets inside our own infrastructure, and it eliminates the risk of a homegrown security bug in our login path. The library itself is a well-tested component — the real cost is the product work around it (enrollment screens, recovery codes, support flows), which we'd scope as a separate, sized effort. It also lets us answer "yes" to MFA controls in enterprise security questionnaires, which unblocks deals.
To engineering:
- It's a primitive, not a feature. We get
generateSecretKey(), getQRCodeUrl(), and verifyKey()/verifyKeyNewer(). We own enrollment, QR rendering, recovery, rate limiting, and UI.
- Two schema decisions land immediately: size the secret column for 32 characters (v9 default; 16 still supported and existing secrets stay valid), and add a last-used-timestamp column if we want replay protection via
verifyKeyNewer().
- Set the
$window validation parameter intentionally — it's a security/UX dial, and the default effectively extends code validity to about 60 seconds.
- We'll pin to the 9.x major, add the Laravel bridge and a QR package as explicit dependencies, and add NTP/time-sync verification to the deploy runbook.
- Expect a small upgrade task per PHP release cycle — the maintainer's support policy drops old majors on a predictable schedule.
- Verify the package's live adoption metrics (downloads, dependents) before we finalize the dependency review; the numbers in our initial export look unreliable.