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

Larainvite Laravel Package

junaidnasir/larainvite

Larainvite is a Laravel package for managing user invitations. It generates invite codes, sends invitation emails, tracks pending and accepted invites, and integrates with registration to control who can sign up.

View on GitHub
Deep Wiki
Context7

Getting Started

Larainvite adds invitation-based registration to a Laravel app: an existing (trusted) user issues an invite, the package mails a tokenised link, and the invitee's token is validated when they complete registration.

Install, matching the new tagging policy. Tags now track the Laravel major, so v12.0.0 is the Laravel 12 line. Constrain accordingly:

composer require junaidnasir/larainvite:^12.0

If you are still on Laravel 10 or 11, install the matching tag (^10.0 / ^11.0) rather than ^12.0 — see Gotchas.

Publish and migrate. Publish the config and the invites migration, then run it:

php artisan vendor:publish --provider="Junaidnasir\Larainvite\LarainviteServiceProvider"
php artisan migrate

Wire up the model. In config/larainvite.php, point user_model at your actual Eloquent user class, then add the package trait and contract to that model:

use Junaidnasir\Larainvite\Traits\HasInvites;

class User extends Authenticatable implements CanBeInvited
{
    use HasInvites;
}

First use case — invite-only signup. From an admin/console command or an "Invite a teammate" form:

$inviter = User::find(1);
$invite  = $inviter->invite('[email protected]'); // creates row + sends mail

Then a public GET /invite/{token} route resolves the token, checks validity, and lets the invitee register. That request/accept flow is the part most teams replace with their own controller — do that before you build anything else on top.

If you only read one thing first, read the published config/larainvite.php: it drives the user model, mail settings, and routing behaviour, and most "it doesn't work" reports come from a stale or missing config.

Implementation Patterns

Custom accept controller instead of the packaged routes. The bundled routes are fine for a spike, but registration flows almost always need extra fields (name, password, tenant). Resolve the invite yourself, validate, then create the user in a transaction:

public function store(Request $request, string $token)
{
    $invite = Invite::get($token);

    abort_unless($invite && $invite->isValid(), 404);

    return DB::transaction(function () use ($invite, $request) {
        $user = User::create([...]);
        $invite->accept();          // flips status, burns the token
        Auth::login($user);
        return redirect()->route('dashboard');
    });
}

Treat accept() / decline() as state transitions, not formality. Call them only after the side effects (user creation, role assignment) succeed, and wrap both in the same transaction. A token that is accepted but leaves no user is unrecoverable without manual DB work.

List and manage pending invites. The relation gives you an easy admin panel and a natural place to add revoke/resend:

$pending = $inviter->invites()->whereNull('accepted_at')->get();

foreach ($pending as $invite) {
    // resend, revoke, show expiry countdown
}

Authorise who may invite. Don't rely on the UI hiding the button. Put a policy or gate in front of the invite endpoint (Gate::authorize('invite', $team)), and rate-limit the route — invite mail is an abuse vector (spam relay, email-enumeration via error messages).

Match the invitee's email to the registration email. Capture the invited email from the invite record and either prefill it read-only or assert it equals the submitted address; otherwise a leaked token lets anyone register with any address.

Integrate with onboarding, not just auth. A common pattern is one invite row carrying the intended role/team, then in the accept transaction assign that role. Keep the role payload in your own table or column if the package's invite record doesn't model it — don't overload the token string.

Mail customisation. Publish the package views/Mailable and swap in your branding, and queue the send (ShouldQueue) if you're issuing invites in bulk. In tests:

Mail::fake();
$this->post('/invites', ['email' => '[email protected]']);
Mail::assertSent(InviteMail::class);

Gotchas and Tips

The version jump is a compatibility signal, not a feature changelog. v7.0.0 → v12.0.0 with "tags will track major Laravel versions" means the number now encodes the supported Laravel major. Two consequences: (1) ^7.0 will not install on Laravel 12 — you must bump the constraint and composer update; (2) intermediate tags (8/9/10/11) are likely Laravel-major markers too, so do not read the number as semver feature progress. Diff the README between your old tag and the new one before upgrading; apart from Laravel 12 support and a README refresh, this release advertises no runtime changes, so expect the upgrade to be low-risk but verify the service provider and config keys still line up.

Pin by Laravel major and record it. Because tags follow Laravel, a Laravel upgrade is a two-step: bump Laravel, bump larainvite. Add a note in your upgrade runbook, otherwise you'll hit composer why-not dead ends mid-upgrade.

Wrong user_model fails quietly. If config/larainvite.php still points at App\User and your model lives at App\Models\User, invite resolution breaks in ways that surface as nulls rather than exceptions. Check this first after any namespace refactor.

Token table collisions on publish. The published migration is timestamped at publish time; if you already have an invites table from a previous version or a hand-rolled schema, you'll get a duplicate-table error. Diff the migration rather than blindly re-publishing.

Double-accept races. Two concurrent requests with the same token can both pass isValid() before either writes. Use lockForUpdate() on the invite row (or a unique constraint on accepted state) inside the transaction.

Email comparison. Compare case-insensitively and trim; an invite for [email protected] failing to match [email protected] at registration is a classic support ticket.

Expiry and timezones. Validity depends on the invite's expiry timestamp. Make sure the column is cast in your app timezone expectations, and expose a clear "invite expired — ask your admin to resend" message instead of a generic 404.

Re-inviting. Decide explicitly whether a second invite to the same email supersedes the first. If the package doesn't enforce it, invalidate older pending rows yourself so only one live token exists per email.

Debugging. When an invite "isn't working", inspect the invites table directly — row exists? accepted/declined set? expiry passed? — before touching application code. Distinguish Invite::get($token) returning null (no such token) from a model that exists but is invalid (used/expired); they deserve different user-facing errors.

Extension points. The config file and the published mail views are the supported knobs; the package exposes little beyond them. Anything richer (invite metadata, per-team invites, audit trail) should live in your own adjacent table keyed by invite id, not in a fork — forking is now awkward because the package version moves in lockstep with Laravel.

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
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource