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

tapp/filament-invite

A Filament plugin that adds invitation-based user registration to your admin panel: generate and email invite links, track pending and accepted invitations, and let invited users register securely. Manage invitations through Filament resources with Laravel notification support.

View on GitHub
Deep Wiki
Context7

Getting Started

The package replaces "create user with a password" with "send a signed invitation link that lets the invitee set their own password." That is the whole value proposition, so evaluate it against your existing onboarding flow before wiring it in.

Install and publish

composer require tapp/filament-invite
php artisan vendor:publish --provider="Tapp\FilamentInvite\FilamentInviteServiceProvider"
php artisan migrate

Expect a config file (config/filament-invite.php) and an invitations migration. Read the config file before anything else — it defines the invitation model, the notification class, token/link expiry, and which panel/guard the links resolve against. Most "it doesn't work" issues trace back to a key in this file.

Register the plugin

// app/Providers/Filament/AdminPanelProvider.php
public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(FilamentInvitePlugin::make());
}

Where to look first, in order

  1. config/filament-invite.php — model classes, expiry, guard, redirect-after-accept.
  2. The plugin class (src/…Plugin.php) — what it actually registers (resource actions, routes, middleware).
  3. The accept controller/route — this is where the signed URL is validated and the password is set.
  4. The notification class — the only thing your users will see.

First use case: open your Users resource in the panel, hit the invite action in the table header, invite yourself to a second email address, and complete the flow end to end in a browser with MAIL_MAILER=log. Do this before inviting a real teammate; it surfaces mail, URL, and guard problems in five minutes instead of five days.

Implementation Patterns

Invite from the Users resource (the 90% case). The plugin adds a table/header action. Keep it there rather than building a bespoke page — you inherit Filament's modal, validation, and notifications for free. Add ->visible(fn () => auth()->user()->can('invite', User::class)) if you need policy gating; the package won't infer your policies.

Invite programmatically. Typical shape:

use Tapp\FilamentInvite\Facades\FilamentInvite;

FilamentInvite::invite($email, panel: 'admin');

Use this for imports, CRM webhooks, or seeding QA accounts. Wrap it in a job and let the notification queue rather than blocking a request on SMTP.

Bulk invites. Either loop the facade inside a job, or add Filament's BulkAction that maps selected records to invite calls. Deduplicate on email first — see the gotchas.

Customise the notification. Publish/override the notification class and point the config at yours. This is where branding, tenancy context ("you've been invited to Acme's portal"), and copy live. Keep it queued (ShouldQueue) and include the panel name in the subject so recipients with multiple accounts can tell the links apart.

Hooks on accept. The accept flow is the right place to attach side effects — assigning a default role, adding the user to a tenant/team, stamping invited_by, firing an analytics event. Prefer a model event or a listener on the package's accept event over forking the controller; forking means re-fixing it on every upgrade.

Multi-panel / multi-guard. If you run admin and app panels, invitations must be scoped to the panel whose guard the user will authenticate against. Store the panel id on the invitation row (the package supports this via config) and assert it when generating and when accepting.

Roles on accept. Invitations should not grant authority by themselves. Record the intended role on the invitation (or in a meta JSON column you control), apply it in an accept listener, and let your normal policy layer handle everything after.

Testing pattern.

Notification::fake();
$this->actingAs($admin)->livewire(InviteUser::class)->callAction('invite');
Notification::assertSentTo(User::where('email', $email)->first(), InvitationNotification::class);

Then $this->travel(expiry + 1)->minutes() and assert the accept route 403s.

Gotchas and Tips

Email "not sent." Nine times out of ten it's MAIL_MAILER=log, or the notification is queued and no worker is running. Check storage/logs/laravel.log and jobs table before touching package code.

Signed-URL mismatch. APP_URL differing from the host you're browsing on invalidates signed links. Same for reverse proxies that don't forward X-Forwarded-* — set TrustProxies correctly or every invite link in production will 403.

Expiry is a config value, not a per-invite one. If you need different lifetimes for "normal" vs "VIP" invites, you'll be overriding at the call site or patching the token creation, not just flipping a config flag.

The User model must already be Filament-authneticatable. The invitee record is a normal user — it needs FilamentUser, canAccessPanel(), and whatever tenancy/role plumbing your panel expects. Inviting someone who then hits a 403 on the panel is an onboarding bug, not an invite bug. Add a test that asserts a freshly-accepted user can reach the panel dashboard.

Duplicate/conflicting invitations. You will get them: an invited-but-not-accepted user, then a second invite, then a manual creation. Decide explicitly whether re-inviting reuses the row and refreshes the token or creates a new one — and enforce it with a unique index on (email, panel) or a soft-delete-then-insert. Silent duplicates produce two valid links and confusing expiry behaviour.

Password reset ≠ invitation. They use different brokers and tokens. If a user clicks "forgot password" before accepting, they'll set a password but may still lack the role/tenant your accept hook was supposed to assign. Make the accept hook idempotent, and consider rejecting password resets for users with a pending invitation.

Rate-limit and don't leak. The accept route is public. Rate-limit it, and make sure invalid/expired tokens return a generic error rather than echoing the email address.

Extension points to reach for before forking: custom invitation model (extend the package model, point config at it), custom notification class, and the accept event/listener. Forking the controller or the Livewire resource action is a maintenance tax on every Filament major upgrade.

Upgrade discipline. This package's blast radius is your auth surface, and its release cadence tracks Filament majors. Pin it in composer.json, read the diff on minor bumps, and keep your own end-to-end invite test in CI — that test is what tells you an upgrade broke the flow, not the changelog.

Small team, small community. 32 stars, no dependents: expect to read the source rather than the docs when behaviour surprises you. Budget half a day for that on first integration, and keep your customisations in config plus one listener file so you can re-read them fast.

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