Trait verbs and actions
HasTwoFactorAuthentication exposes the same lifecycle on the user itself. Every verb delegates to TwoFactor::for($this) — never straight to an action — so TwoFactor::fake() records it and your action overrides still apply:
$setup = $user->startTwoFactorEnrolment(); // → TwoFactorSetup (== ->start())
$user->confirmTwoFactor($code); // == ->confirm()
$result = $user->attemptTwoFactorCode($code); // → VerificationResult (== ->attempt())
$ok = $user->verifyTwoFactorCode($code); // bool (== ->attempt()->verified)
$user->disableTwoFactor(); // == ->disable()
$codes = $user->regenerateTwoFactorRecoveryCodes(); // == ->recoveryCodes()->regenerate()
$user->twoFactorRecoveryCodesRemaining(); // int| Method | Returns | Purpose |
|---|---|---|
startTwoFactorEnrolment(?string $label = null, ?string $issuer = null) | TwoFactorSetup | Begin (or restart) a pending enrolment — ->start(). |
confirmTwoFactor(string $code) | void | Confirm the pending enrolment with the first code — ->confirm(). |
attemptTwoFactorCode(string $code) | VerificationResult | Login challenge — TwoFactor::for($this)->attempt(). |
verifyTwoFactorCode(string $code) | bool | Login challenge — exactly ->attempt($code)->verified. |
disableTwoFactor() | void | Clear all two-factor state — ->disable(). |
regenerateTwoFactorRecoveryCodes() | list<string> | Replace the recovery codes, returning the new set once — ->recoveryCodes()->regenerate(). |
twoFactorRecoveryCodesRemaining() | int | How many single-use recovery codes remain. |
hasTwoFactorEnabled() | bool | A secret is set and confirmed. |
hasPendingTwoFactor() | bool | A secret is set but not yet confirmed. |
twoFactorSecret() | ?string | The decrypted base32 secret. |
twoFactorRecoveryCodes() | list<string> | The stored codes — hashes in hashed mode. |
twoFactorLabel() | string | The provisioning label — email, then primary key. Override to customise. |
twoFactorCasts() | array<string, string> | The casts to spread into the model’s casts(). |
Pass a label and/or an issuer to startTwoFactorEnrolment(), or override twoFactorLabel() on the model to key the provisioning URI on a username or phone instead of the default (email, then primary key).
The actions behind them
Each write verb ends in one action class — StartEnrolment, ConfirmEnrolment, AttemptTwoFactorCode, RegenerateRecoveryCodes or DisableTwoFactor. Call those directly when composing your own actions or jobs; the full mapping is in DI and actions.
Disabling clears every two-factor column — secret, recovery codes, confirmation and the replay marker — so an admin can reset a compromised account in one call and the user can re-enrol cleanly.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.