pull('2fa.codes_fresh', false)) { $this->dispatchCodes(); } } /** Regenerate the current user's backup codes (invalidates the old set). */ public function regenerate(): void { Auth::user()->replaceRecoveryCodes(); AuditEvent::create([ 'user_id' => Auth::id(), 'actor' => Auth::user()->name ?? 'system', 'action' => 'two_factor.recovery_regenerate', 'target' => Auth::user()->email, 'ip' => request()->ip(), ]); // One-time download grant (a timestamp) for the freshly regenerated set, consumed by // the download route within a short window. Without it a later direct hit 403s. session()->put('2fa.download_grant', now()->timestamp); // Reveal the freshly generated set once, via the transient event (never a property). $this->dispatchCodes(); $this->dispatch('notify', message: __('auth.recovery_regenerated')); } public function render() { return view('livewire.modals.recovery-codes'); } /** * Deliver the current user's recovery codes to the browser via a one-time event. The * codes never enter a Livewire property or the snapshot — Alpine holds them in JS memory * only, so a replayed snapshot cannot re-render them. */ protected function dispatchCodes(): void { $this->dispatch('reveal-codes', codes: Auth::user()->recoveryCodes()); } }