Open-source project
spatie/laravel-welcome-notification avatar
spatie/laravel-welcome-notification

laravel-welcome-notification: a first-login password link for Laravel

Send a welcome notification to new users

595 stars46 forksPHPMIT

At a glance

What is it?
spatie/laravel-welcome-notification sends a new user a mail containing a secure link to a screen where they set an initial password, with the link expiring on a date you choose. The package supplies the notification, the controller and the form view, and leaves the routes, the styling and the user model wiring to you.
Who is it for?
laravel-welcome-notification suits a Laravel application that provisions users itself and needs them to choose a password on first contact, without building a token flow by hand. It is a poor fit for applications that already have a working activation or invitation flow, since the two will fight over the same onboarding step, and it is a poor fit if you want more than a password in the form without touching a published view and writing validation rules.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A mail with a link, not a generated password

The package does one small thing: it sends a `WelcomeNotification` to a new user of your app, and that notification contains a secure link to a screen where the user can set an initial password.

The call is two lines:

php
$expiresAt = now()->addDay();

$user->sendWelcomeNotification($expiresAt);

The design decision worth noticing is that the user chooses the password rather than receiving a generated one. The alternative, mailing a temporary password, puts a credential in a mailbox that the user may not check immediately, and it makes the first login a reset rather than a first password. Here the link is a one-time action that ends with the user holding a password they picked.

The expiry date is an argument rather than a configuration setting, which means the lifetime of the link is decided at the moment of sending, per user. The example gives it a day. If you are provisioning accounts in bulk you would probably want a shorter window, and if the link is delivered by a channel that can be delayed you might want a longer one.

The package is MIT licensed, it is on Packagist, and the upstream project publishes a walkthrough on sending a welcome notification to new users of a Laravel app, linked from the repository description.

Installation is composer plus one published migration

The package installs with composer:

bash
composer require spatie/laravel-welcome-notification

It ships migrations, and you have to publish them yourself:

bash
php artisan vendor:publish --provider="Spatie\WelcomeNotification\WelcomeNotificationServiceProvider" --tag="migrations"

Then you migrate the database:

bash
php artisan migrate

The publishing step is not optional, and the readme is direct about that: you must publish the migrations provided by the package. That is the usual pattern for a package that owns a table, and it has the advantage that you can read the schema before it lands in your database.

The same mechanism is used for the views later on, with the tag set to `views` instead:

bash
php artisan vendor:publish --provider="Spatie\WelcomeNotification\WelcomeNotificationServiceProvider" --tag="views"

So there are two publish steps, one for the schema and one for the templates, and the second one is optional in the sense that the package can render its own welcome form if you never publish it.

Three pieces of wiring belong to your application

The package handles the notification and the form, but three things are deliberately left to the application.

First, the user model. You must apply the `\Spatie\WelcomeNotification\ReceivesWelcomeNotification` trait to your `User` model, which is what gives it the `sendWelcomeNotification` method you call.

Second, the controller. You create a controller of your own that extends `Spatie\WelcomeNotification\WelcomeController`, and that controller is used to show the welcome form and to save the password a user sets:

php
namespace App\Http\Controllers\Auth;

use Spatie\WelcomeNotification\WelcomeController as BaseWelcomeController;

class MyWelcomeController extends BaseWelcomeController
{
}

Third, the routes. You register them yourself, wrapped in a group with the `web` middleware and the package's own `WelcomesNewUsers` middleware:

php
use Spatie\WelcomeNotification\WelcomesNewUsers;
use App\Http\Controllers\Auth\MyWelcomeController;

Route::group(['middleware' => ['web', WelcomesNewUsers::class,]], function () {
    Route::get('welcome/{user}', [MyWelcomeController::class, 'showWelcomeForm'])->name('welcome');
    Route::post('welcome/{user}', [MyWelcomeController::class, 'savePassword']);
});

That design has a practical payoff. Because the routes and the controller are yours, the welcome screen can live wherever your application expects it, sit behind whatever middleware your organisation already applies, and be extended without patching the package. The cost is that the four steps of the readme have to be done in order, and forgetting the middleware is the kind of omission that quietly removes a check.

The link carries a route parameter, so the URL matters

The route is `welcome/{user}`, a GET and a POST on a path with the user in it, and the link in the mail points at it. The user model and the expiry date travel with the notification.

That is worth thinking about before you ship it, because it decides what your logs and your browser history contain. A URL of the form `/welcome/123` names the account being set up, and the notification also carries a token that authorises the action, since the middleware is named for welcoming new users and the readme describes the link as secure.

The documentation does not describe the internals of that token, so the details of how the link is validated, whether it can be used more than once, and what happens when it is used after the expiry date are not documented here. If those answers matter to you, they are questions for the package's own documentation or for the maintainers, and you should not assume the behaviour you want.

The one behaviour that is documented is the extension point after a successful password change. After the user has successfully set a new password, the `sendPasswordSavedResponse` of the `WelcomeController` is called, and you override it to decide what happens next, for example a redirect to a home route. The same pattern of override applies to validation, which is the subject of the next step.

Customising the mail means subclassing the notification

By default the `WelcomeNotification` sends a mail. To change it you extend `WelcomeNotification` and override the `buildWelcomeNotificationMessage` method:

php
use Illuminate\Notifications\Messages\MailMessage;

class MyCustomWelcomeNotification extends WelcomeNotification
{
    public function buildWelcomeNotificationMessage(): MailMessage
    {
        return (new MailMessage)
            ->subject('Welcome to my app')
            ->action(Lang::get('Set initial password'), $this->showWelcomeFormUrl);
    }
}

The action button label is translated through `Lang::get`, and the URL comes from the notification's own `showWelcomeFormUrl` property, so the link stays the package's business even when the wording is yours.

Using the custom notification means adding a `sendWelcomeNotification` method to your `User` model, which replaces the one the trait provides:

php
public function sendWelcomeNotification(\Carbon\Carbon $validUntil)
{
    $this->notify(new MyCustomWelcomeNotification($validUntil));
}

Note the type on the argument. The expiry is a `\Carbon\Carbon` instance, so the date you computed with `now()->addDay()` is passed straight through, and the notification decides what to do with it.

The pattern here, override a message builder and override a response method, is the same shape as the controller extension, and it is a reasonable way for a package to offer a default that is still adjustable: you never edit the package's files, you subclass them.

Extra form fields need a published view and your own rules

The default welcome form that ships with the package only asks for a password. To collect more, you publish the view and add fields to it, which is the point where the package stops being turnkey.

Validation is then handled by overriding the `rules` function in your own `WelcomeController`. The readme gives an example with an extra field named `job_title`:

php
class MyWelcomeController extends BaseWelcomeController
{
    public function rules()
    {
        return [
            'password' => 'required|confirmed|min:6',
            'job_title' => 'required',
        ];
    }
}

The password rule that ships by default is worth reading closely, because it is a floor rather than a policy. `required` says a password must be present, `confirmed` means the form must include a matching confirmation field, and `min:6` sets a minimum length of six characters. Six is a short minimum by most current guidance, and since the rules method is yours to override, that is the place to raise it if your application requires more.

The `confirmed` rule also means the published view has to include a confirmation input, which is a detail worth checking the first time the form fails validation with a message about confirmation.

Testing, support and the release cadence

The package documents a single test command:

bash
composer test

The repository is a conventional PHP package: a `src` directory with the implementation, a `database` directory for the migrations, a `resources` directory for the views, a `tests` directory and a `phpunit.xml.dist` for the test configuration. There is also a `composer.json`, a `CHANGELOG.md` for what changed in each version, and a `CONTRIBUTING.md` link to the maintainer's shared contributing guidelines.

The licence is MIT, with the licence file at the root, which for a package like this is the least friction arrangement: you can use it in a proprietary application without obligations beyond the notice.

The release history shows a steady but slow line. Version 2.4.3 was tagged on 2025-02-20, 2.4.4 on 2025-02-26 and 2.5.0 on 2026-02-22, and the last push was on 2026-06-02. The repository is not archived, and the default branch is `main`.

The security policy is worth noting: if you find a bug regarding security you should mail the address in the readme rather than using the issue tracker. For a package that handles a password-setting link, that is the right channel, and it is the one to use if you find a problem with how the token is generated or how the middleware validates it.

Editorial conclusion

laravel-welcome-notification suits a Laravel application that provisions users itself and needs them to choose a password on first contact, without building a token flow by hand. It is a poor fit for applications that already have a working activation or invitation flow, since the two will fight over the same onboarding step, and it is a poor fit if you want more than a password in the form without touching a published view and writing validation rules. Before you install it, decide where the welcome route lives, since the link is built from a route that you register, and read the package's own notes on the `WelcomesNewUsers` middleware so you know what the package checks before it renders the form.

Frequently asked questions

What does spatie/laravel-welcome-notification do?

It sends a `WelcomeNotification` to a new user of your app, containing a secure link to a screen where the user sets an initial password. You call `$user->sendWelcomeNotification($expiresAt)` with the date the link should expire.

What do I have to set up in my Laravel application?

Publish and run the migrations, apply the `ReceivesWelcomeNotification` trait to your User model, create a controller extending `Spatie\WelcomeNotification\WelcomeController`, and register the welcome routes yourself inside a group with the `web` and `WelcomesNewUsers` middleware.

How do I change the welcome email?

Extend `WelcomeNotification` and override the `buildWelcomeNotificationMessage` method to return your own `MailMessage`, then add a `sendWelcomeNotification` method to your User model that notifies with your custom notification class instead of the default one.

Can the welcome form ask for more than a password?

Yes. Publish the views and add fields to the form, then override the `rules` function in your own WelcomeController to validate them. The example in the readme adds a required `job_title` field alongside the password rules.

What happens after the user sets their password?

The `sendPasswordSavedResponse` of the `WelcomeController` is called, and you override that method in your own controller to decide what happens next, for example redirecting to a home route.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. spatie/laravel-welcome-notification on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/spatie-laravel-welcome-notification.svg)](https://hysenlabs.com/projects/spatie-laravel-welcome-notification)

Was this useful?