eddusoft/filament-access-control-2fa
Filament plugin that adds access control with two-factor authentication, helping you secure admin panels and manage user permissions. Extend Filament resources and panels with 2FA challenges and role-based access restrictions, keeping sensitive areas protected while staying simple to configure.
The package is a Filament panel plugin that bolts TOTP 2FA and access control onto an existing Filament panel. It assumes you already have Filament v3 installed and working — do not attempt to bootstrap a project from this package alone. At v1.0.1 the identity of the package is still moving (the release note is literally "Change the package name to publish it"), so treat install as an exploratory step, not a production commitment.
Minimal setup sequence:
Pin the exact tag. Floating constraints are unsafe here given the rename in v1.0.1. In composer.json:
"require": {
"eddusoft/filament-access-control-2fa": "1.0.1"
}
Do not assume the old v1.0.0 name resolves. If you previously installed v1.0.0, remove that requirement first, composer clear-cache, then require the new name.
Verify auto-discovery. After composer install, check bootstrap/cache/packages.php contains the (new) provider. If not, run php artisan package:discover. On any deploy pipeline that ships a prebuilt cache, force a rebuild rather than a restart — a stale cache silently disables the plugin and you get "class not found" at request time.
Publish config and migrations. Read the README for the exact tags — Filament package conventions usually give you something like:
php artisan vendor:publish --tag="filament-access-control-2fa-config"
php artisan vendor:publish --tag="filament-access-control-2fa-migrations"
php artisan migrate
Verify the tags against the repo — they may embed the old name if the rename was metadata-only.
Register the plugin on the panel in your PanelProvider:
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentAccessControl2FaPlugin::make());
}
Wire the user model. Whatever contract the package expects (an interface/trait, or a configurable enforce_2fa flag) needs to be applied to your User model. This is the step most likely to break if the package assumed a specific user model shape.
First use case to prove out: a single admin user enables 2FA via the Filament profile page, scans the QR with an authenticator app, gets recovery codes shown once, logs out, and logs back in completing the TOTP challenge. If that loop doesn't close cleanly in half a day, stop — this is the whole value of the package.
Panel-level enforcement is the primary day-to-day lever. Once registered, a panel ->plugin(...) call is the single point where 2FA gets switched on for that panel's users. Keep it in the dedicated PanelProvider (AdminPanelProvider, StaffPanelProvider) rather than a global provider so you can roll it out panel-by-panel — e.g. admins get enforcement day one, an internal tools panel stays opt-in.
Role-based enforcement. "Enforcement options for users, roles, or panels" means you'll want a pattern like:
spatie/laravel-permission)Wrap the role lookup behind your own helper (User::requiresTwoFactor()) rather than scattering permission checks through Filament resources — you want exactly one place to change the policy.
Opt-in enrollment flow for users who aren't enforced: a Filament page/action that shows the QR + secret, then requires the user to submit a valid code before persisting the secret. Persisting on QR display alone is the classic bug — a user scans nothing, closes the tab, and is locked out next login.
Recovery codes: generate on enrollment, display exactly once, store hashed (or at minimum encrypted). Standard pattern:
If the package doesn't do hashing or single-use out of the box, add it at your boundary — don't trust the default.
Access control integration. Two separate uses:
canAccessPanel(), not replace it.canAccess() / policies for sensitive resources (billing, user management). Keep policies as the source of truth; treat this package's access control as an additional gate, not a shadow authorization system.Testing pattern. The non-negotiable workflow for a day-to-day package like this:
pestphp/pest-plugin-livewire or Filament's own testing helpers to click through the Filament login flow.$this->travelTo(...)) so TOTP windows are deterministic.pragmarx/google2fa or otplib/spomky-labs/otphp) using the user's stored secret, rather than mocking the package's internals./admin without TOTP; user who redeems a recovery code can." That single test is your alarm when a patch release breaks the contract.Feature-flag it. Given the v1.0.x churn, put the plugin registration behind a config flag or your own thin TwoFactorGate interface. If the package is abandoned or the API shifts, removing it becomes a config flip plus deleting one test.
The rename is the first gotcha, not the last. v1.0.1 changed the Composer package name in a patch release. That means:
composer show for both.use statements after upgrading if you consumed v1.0.0.Clearing caches after every install/upgrade:
php artisan config:clear
php artisan cache:clear
php artisan view:clear
composer dump-autoload
php artisan package:discover
Missing any of these is the #1 cause of "the plugin is installed but nothing renders."
TOTP clock skew. Authenticator apps and server clocks drift. Most TOTP libraries accept ±1–2 windows by default; if users report "invalid code" on otherwise-correct apps, widen the verification window (config knob) before touching anything else. Never widen past ±2 — it materially weakens the second factor.
Lockout is the top operational risk. Enforce 2FA and you will eventually lock out an admin. Plan for it before rollout:
php artisan tinker or a custom command2fa:disable {user} artisan command you own, not trusting the package to ship oneEnrollment must be verified, not just initiated. Confirm the user submitted a valid code before persisting the secret. This is the single most common 2FA integration defect.
Recovery code edge cases:
Filament version drift. Filament v3 plugin APIs (the Plugin contract, panel ->plugin(), profile page composition) changed from v2. Confirm the package targets v3 specifically. If the README doesn't state a Laravel major / Filament major matrix, assume nothing beyond your own installed versions and pin accordingly.
Extension points to prefer. Where the package exposes hooks (config keys, a customizable User contract, events for TwoFactorEnabled / RecoveryCodeUsed), hook into them instead of overriding the package's pages or extending its internals. You'll survive a v1.0.2 bump; a forked page class you won't.
Logging and observability. Log enrollment, disable, and recovery-code-use events at info with the user id. When someone claims they got locked out or their codes were used, this is the only evidence you'll have.
Watch the repo, not just the tag. Score of 0.7 and 0 stars means this is likely a single-author, pre-traction package. Set a GitHub release-watch or a calendar reminder to re-check before you depend on it beyond a pilot. Two consecutive substantive patch releases with no identity churn is your signal to promote it past staging.
How can I help you explore Laravel packages today?