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 Passwordless Laravel Package

bradyrenting/filament-passwordless

Passwordless authentication for Filament panels. Let users sign in with secure email magic links or one-time codes instead of passwords, reducing friction and login security risks. Laravel-native, easy to install, and designed to integrate with existing Filament auth flows.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and publish.

composer require bradyrenting/filament-passwordless
php artisan vendor:publish --tag="filament-passwordless-config"

Check whether the package ships migrations (vendor:publish --tag="filament-passwordless-migrations") — if it stores tokens or login nonces in a table you must run php artisan migrate before anything works, and the failure mode is a silent 500 on the login POST rather than a helpful error.

Where to look first. Read the config/filament-passwordless.php that gets published before you touch any panel provider. That file is the real API surface: link lifetime, the notification/mailable class, the route prefix and middleware, and usually a toggle for whether the plain password field stays available. Then read src/ — packages at this size are typically a few hundred lines wrapping Laravel's URL::temporarySignedRoute() plus a Filament login page override, so ten minutes in the source will tell you more than the README.

First use case. Swap Filament's default login page for the package's so users type only an email address, receive a signed link, and land authenticated in the panel.

// app/Providers/Filament/AdminPanelProvider.php
public function panel(Panel $panel): Panel
{
    return $panel
        ->login(\Bradyrenting\FilamentPasswordless\Pages\PasswordlessLogin::class)
        // ...
}

Wire the User model to whatever contract or trait the package expects (typically CanLoginPasswordless or a passwordless opt-in column). Verify against the README for your installed version — the class names move between 0.x releases.

The single best smoke test: set MAIL_MAILER=log, request a link, tail storage/logs/laravel.log, copy the URL, paste it into a private window. This isolates link generation from mail delivery in one step.

Implementation Patterns

Keep the password path alive during rollout. Most teams run both: password login for admins and service accounts, magic links for end users. The panel-level ->login() swap is all-or-nothing, so if the package exposes a fallback flag in config, use it; otherwise register the package page at a distinct route (e.g. /admin/magic-login) and link to it from the standard login form. Migrating every account to passwordless at once tends to break CI users, seeders, and anyone whose mail is slow.

Queue the notification. If the mailable is synchronous, a slow SMTP host blocks the Livewire request and users double-submit. Point the package at your own queued notification via the config key and implement ShouldQueue. This also gives you a natural place to add your own mail template, from-name, and reply-to.

Customize the notification, not the core. The correct extension point for branding is the notification class named in config. Subclass it, override toMail(), and swap the binding. Editing vendor/ will be wiped by the next composer update, and with 26 stars and a pre-1.0 version line, updates will be frequent.

Multi-panel and multi-guard. If you have separate admin and app panels on different guards, confirm which guard the package authenticates against. In practice you will want the login page resolved per-panel and the signed route's middleware to match; a guard mismatch produces the confusing "link valid, still redirected to login" loop.

Test with fakes.

Notification::fake();

$this->post('/admin/login', ['email' => $user->email])->assertSessionHasNoErrors();

Notification::assertSentTo($user, MagicLinkNotification::class);

Then hit URL::temporarySignedRoute(...) directly in a feature test with $this->get($url)->assertAuthenticated(), plus a negative test with a tampered signature and an expired expires parameter. Those two tests catch ~80% of real-world breakage.

Local development. Keep MAIL_MAILER=log in .env.testing and .env.local. Consider a local only config override that shortens link lifetime to 60 seconds so you notice expiry behaviour before production users do.

Gotchas and Tips

Email enumeration. By default these packages often respond differently for a known versus unknown address (validation error vs success redirect). That leaks your user list. Force an identical response and swallow the "no such user" case — send nothing, redirect to the same "check your inbox" page.

Signed URLs are stateless and therefore reusable. A temporary signed link is valid for its whole lifetime and can be replayed by anyone who gets hold of it (forwarded mail, shared inbox, mail scanner prefetching URLs). If the package does not implement a single-use nonce, add one: a passwordless_tokens table or a last_login_token_hash column checked in the link's route handler. Corporate mail scanners that pre-fetch links will otherwise burn users' tokens before they click — a classic and very hard-to-diagnose support ticket.

APP_URL and proxies. Signature validation includes the host. Behind a load balancer without TrustProxies configured, links generated as http:// fail signature checks when accessed over https://. Set APP_URL correctly, configure trusted proxies, and force https in non-local environments.

Expiry and clock skew. Default lifetimes are usually 15–60 minutes. If your app servers' clocks drift, links fail at the edge of the window. Keep expiry generous enough (30 min) that mail delays don't matter, and make the expiry error message actionable ("link expired, request a new one") rather than a bare 403.

Interaction with 2FA and remember. Passwordless login typically bypasses Filament's password confirmation and any remember me checkbox. If you require 2FA for privileged users, you must explicitly re-trigger the challenge after authentication, or you have silently removed a security control. Audit this before shipping.

Config caching. After editing the published config, run php artisan config:clear — a stale cached config is the number one reason "my changes do nothing" in Laravel packages generally.

Version pin tightly. At 26 stars and pre-1.0, treat the package as a thin convenience wrapper and pin an exact version in composer.json. Read the source before upgrading minors. If the dependency becomes a liability, the entire feature is ~150 lines: a temporary signed route, a controller that calls Auth::login(), and a notification. Forking or inlining it is often cheaper than debugging an unmaintained abstraction.

Debugging checklist, in order: config cached? → mail actually sent (check the log driver)? → host/scheme matches APP_URL? → signature valid (check the signature query param survives mail-client rewriting)? → token already consumed by a scanner? → correct guard? Work down that list and you'll resolve nearly every reported issue.

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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle