Skip to main content

Installation

Requirements

ComponentConstraint
PHP^8.4 (8.4 and 8.5)
Laravel^13.0
Laravel Fortify^1.0 — optional, only for the two-factor handoff

The package requires laravel/framework (for the FormRequest base it validates with) and adds no third-party runtime dependencies. Fortify is a suggested dependency: the core never references a Fortify symbol unless Fortify is installed and the bridge is enabled.

Install the package

composer require pushery/email-magic-link-for-laravel

Then run the installer to publish the configuration and print the next steps:

php artisan email-magic-link:install

Now run your migrations to create the token table. The migration ships with the package and is loaded automatically — you do not need to publish it first:

php artisan migrate

Add --views to the installer to also publish the Blade views. Prefer to do it by hand? The individual publish tags are still available:

php artisan vendor:publish --tag=email-magic-link # everything at once
php artisan vendor:publish --tag=email-magic-link-config
php artisan vendor:publish --tag=email-magic-link-migrations
php artisan vendor:publish --tag=email-magic-link-views
php artisan vendor:publish --tag=email-magic-link-lang

Publish the migrations only if you need to change them. The package loads its bundled migrations itself, and the published copies get a fresh date prefix, so both would be pending for the same tables; once a published *_create_magic_link_tokens_table.php exists the package stops loading its own. If you rename that file, say so explicitly by calling EmailMagicLinkServiceProvider::ignoreMigrations() in a service provider's register().

The command's full option list is in the command reference.

Run a queue worker

The magic-link email is dispatched to the queue. This is deliberate: the request that issues a link returns in constant time and never blocks on the mailer, so it cannot reveal whether an account exists. The trade-off is that the mail is only actually sent once a queue worker processes the job, so a worker has to be running:

php artisan queue:work

If nothing is consuming the queue, the email never leaves — the request still succeeds, but the job just sits there. In production, keep a worker (or Horizon or Supervisor) running. For local development you can send mail synchronously instead by setting QUEUE_CONNECTION=sync in your .env.

Next