juliomotol/filament-password-confirmation
Adds password confirmation to Filament actions and pages, prompting users to re-enter their password before sensitive operations. Simple setup via a reusable action or page trait to protect critical admin panel tasks.
Re-entry confirmation for sensitive Filament actions: the package gives you a password field you can drop into an action's modal form (or any Livewire form) that validates the submitted value against the currently authenticated user's hashed password.
composer require juliomotol/filament-password-confirmationcomposer.json matches your app (this package rides on Filament's form/action APIs — check before bumping Filament majors).DeleteAction or a "revoke API token" action that currently only uses ->requiresConfirmation().use Filament\Actions\Action;
Action::make('deleteAccount')
->requiresConfirmation()
->form([
// exact FQCN per README — verify the import before copying
PasswordConfirmation::make('password'),
])
->action(fn () => $this->account->delete()),
The mental model: this replaces Laravel's password.confirm middleware for the action layer, where middleware can't reach.
Action modal form (the primary pattern). Because the field lives in the action's form(), Filament's existing modal lifecycle handles validation, error display, and reset. No custom redirect-to-confirm-page flow.
Centralise it in a reusable action/trait. Once you're gating three or four actions, stop duplicating the schema:
trait ConfirmsPassword
{
protected function confirmPasswordField(): array
{
return [PasswordConfirmation::make('password')->revealable()];
}
}
Pair with ->visible() / policy checks, not instead of them. Password confirmation is a "are you still the person at the keyboard" check, not authorisation. Keep ->authorize()/policies doing the permission work; the field answers a different question.
Custom page or standalone Livewire form. Anywhere Filament renders a schema (Filament\Forms\Concerns\InteractsWithForms), the field works the same — useful for "danger zone" settings pages that submit several changes at once.
revealable() (new in v1.2.0). Adds the eye toggle so users can check what they typed. Use it on confirmation fields where typo-driven failures are common (long passphrases, password-manager paste failures). Leave it off if you have a policy against plaintext display on shared screens — it's opt-in, so existing fields are unchanged by the upgrade.
Testing. Drive it through Filament's Livewire test helpers so you cover both the reject and accept paths:
livewire(ListUsers::class)
->callTableAction('delete', $user)
->fillForm(['password' => 'wrong-password'])
->callMountedAction()
->assertHasFormErrors(['password']);
// and the success path
->fillForm(['password' => 'correct-password'])
->callMountedAction()
->assertHasNoFormErrors();
->visible(fn () => filled(auth()->user()->password))) or these users get a permanently unusable action.RateLimiter/throttle on the action if that matters for your threat model.->modalHeading() or persisted form state, verify the password field isn't prefilled from a previous invocation.revealable() is cosmetic only (v1.2.0). It flips the input type to text; hashing, validation, and error behaviour are untouched. Don't treat it as a security setting.fetch-metadata) — no breaking changes, no migrations, no config changes. Safe patch from v1.1.0.->rules()), subclass the field rather than forking the package — it's a single form component, so overriding is cheap.Hash::check() semantics first: the stored hash's driver must match your HASH_DRIVER, and users imported with a different algorithm will fail silently.How can I help you explore Laravel packages today?