Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Webauthn Laravel Package

moontechs/filament-webauthn

moontechs/filament-webauthn brings WebAuthn passkey authentication to Filament panels. Users register and sign in with fingerprint, face recognition, or a hardware security key instead of passwords, adding phishing-resistant, passwordless login to your admin panel with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and its migration, then wire it into a Filament panel:

composer require moontechs/filament-webauthn
php artisan vendor:publish --tag="filament-webauthn-migrations"
php artisan migrate

Register the panel plugin in your PanelProvider (typically app/Providers/Filament/AdminPanelProvider.php):

use Moontechs\FilamentWebauthn\WebauthnPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(WebauthnPlugin::make())
        // ...
}

Add the package's trait to your authenticatable model so it can own credentials:

use Moontechs\FilamentWebauthn\Concerns\HasWebauthnCredentials;

class User extends Authenticatable
{
    use HasWebauthnCredentials;
}

Where to look first:

  1. The published config/filament-webauthn.php — this is where relying-party (rp_id, rp_name, allowed origins) values live. Set these before testing.
  2. The panel login page after registering the plugin — you should see a passkey/"Sign in with WebAuthn" affordance alongside the password form.
  3. The credentials table migration — confirm the foreign key points at your user model's table.

First use case: log in as a user with a password, navigate to wherever the package registers the "add passkey" action (profile/security page or the plugin's default page), register the device, log out, and sign back in with the passkey. If that loop works, the plumbing (HTTPS, RP ID, origin, JS component) is correct.

Implementation Patterns

Passwordless alongside passwords. The common day-one setup is to keep the existing Filament login form and let the plugin append a passkey button. Users enroll a passkey once while authenticated, then can skip the password on subsequent logins. Do not remove password login until you've handled account recovery.

Enrollment as a profile action. Expose passkey registration as a Filament action on a "Security" page or the user resource. Treat it like password change UX:

Action::make('addPasskey')
    ->label('Add a passkey')
    ->modalContent(fn () => view('filament-webauthn::register'))
    ->modalSubmitAction(false);

The actual ceremony runs in the browser via the package's front-end component; the server-side handler validates the attestation and persists the credential against auth()->user().

Multiple credentials per user. Users will have a laptop, phone, and a hardware key. List stored credentials (name, created_at, last_used_at if tracked) and offer delete/rename. Enforce a policy: require at least one other auth method before allowing the last passkey to be deleted.

Requiring WebAuthn as a second factor. Because the plugin authenticates a user directly, the usual pattern is to gate sensitive panels or routes behind "has at least one verified credential" rather than trying to layer it on Filament's 2FA. Check $user->webauthnCredentials()->exists() in a middleware or panel ->authGuard()/access callback.

Reusing the server-side services outside Filament. The package is a thin Filament layer over WebAuthn server-side logic. For a JSON API or a non-Filament guard, call the underlying registration/assertion services directly and skip the Livewire components — but keep the same rp_id/origin config so credentials stay valid across entry points.

Testing. WebAuthn cannot be exercised with plain HTTP feature tests. Use virtual authenticators (Chrome DevTools protocol / @simplewebauthn test helpers) or stub the verification service in PHPUnit. At minimum, cover the persistence path (credential stored, linked to user, rejected when signature invalid).

Gotchas and Tips

  • HTTPS is mandatory except on localhost. WebAuthn will silently fail on http:// staging hosts. This is the #1 "it doesn't work" cause.
  • RP ID and origin must match exactly. Changing your domain, adding a subdomain, or moving from staging.example.com to app.example.com invalidates every existing credential. Set rp_id to the registrable domain (e.g. example.com) and include all valid origins in config before enrollment.
  • Config caching. php artisan config:cache during deploy will freeze RP values; if you change config and see stale behavior, clear it. Same for view caches if you publish and override the JS/components.
  • Filament version compatibility. Filament v2/v3/v4 asset and Livewire changes break plugins quietly. Pin the package and Filament major together, and re-test the login page after every Filament upgrade — the login form is the most fragile integration point.
  • Migration order and user model. If you use a custom users table or a non-User model, update the migration's foreign key and the trait's relation target. Running the migration before your users table exists will fail.
  • Debugging ceremonies. Failures are opaque to users ("something went wrong"). Log the server-side verification exception (WebauthnException) with the challenge and credential ID; inspect the browser console for NotAllowedError/SecurityError which usually map to origin/RP mismatch or user cancellation.
  • Attestation. By default most setups request none attestation. If you want to verify hardware (e.g. only allow YubiKeys), you must configure attestation conveyance and trust anchors — this is a meaningful lift, not a config toggle.
  • Extension points. Override the published views to restyle the button to match your panel, and swap the credential model via config if you need extra columns (device label, last IP). Keep custom columns nullable so the package's save path doesn't break.
  • Account recovery is your problem. Lost device = locked out unless you keep a password fallback or an admin "reset passkeys" action. Build that before rollout, not after the first support ticket.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core