See rates for the top Laravel developers in Latin America

Building a User Invitation System with Laravel

Published on by

Building a User Invitation System with Laravel image

In the not too distant past at ubisend, we needed to build a solution to provide our users the ability to invite additional users to manage their account.

This is a pretty common problem.

Think about a CMS. It’s not much use if you are the only person able to create new content and you certainly don’t want to share your password to allow someone to proof an article.

Similarly, imagine you are building a multitenanted application and want to give your users the ability to add additional members to their team.

Sure, you could build out some CRUD methods for managing users, but wouldn’t it better if you could allow those users to set their own passwords rather than having to send it to them by email, insecurely, in plaintext?

This article will walk you through one approach to building this functionality.

Housekeeping

This task could be carried out in a multitude of ways. At its simplest, we could create a new user record (flagging it inactive) and store a token which is then used in a link to activate the account.

Here, though, we will tackle the problem in a different way using an additional invites table where we will store the user’s email address and activation token. Upon activation, we will use this data to create the new user.

We’ll be using a fresh install of Laravel 5.4, and you will need to have configured your database and mail settings.

Migrations

A default Laravel installation will give us a leg-up for the user migration as it ships by default with the framework.

For this tutorial, remove the name and password fields from the migration:

public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('email')->unique();
$table->rememberToken();
$table->timestamps();
});
}

We do need to create a migration for our invites. On the console from the root of your project, run php artisan make:migration create_invites_table.

This command will create a new migration file in the database/migrations directory. We’ll need to define an incrementing ID, a field to store the new user’s email address and a field for the unique token the new user will use when accepting the invite.

public function up()
{
Schema::create('invites', function (Blueprint $table) {
$table->increments('id');
$table->string('email');
$table->string('token', 16)->unique();
$table->timestamps();
});
}
 
public function down()
{
Schema::drop('invites');
}

Now, on the console from the root of your project, run php artisan migrate.

The database is good to go.

Models

We will need to create Eloquent models for managing both our team and user records.

As with migrations, Laravel ships with a default Eloquent user model so no need to create one.

For the invites model, head back to the console, and from the root of your project run php artisan make:model Invite.

Take a look in the app directory, and you will see your newly created invite model.

All we need to do here is define the fillable fields as follows. This will allow us to mass assign properties when creating updating models.

protected $fillable = [
'email', 'token',
];

Routes

For this tutorial we’ll need to define three routes for the following scenarios:

  • Show the form to invite a new user
  • Process the form submission
  • Accept the invitation

In the app/routes/web.php file, add the following routes:

Route::get('invite', 'InviteController@invite')->name('invite');
Route::post('invite', 'InviteController@process')->name('process');
// {token} is a required parameter that will be exposed to us in the controller method
Route::get('accept/{token}', 'InviteController@accept')->name('accept');

Controller

The eagle-eyed readers will have noticed when defining the routes above we referenced InviteController to process the requests.

That controller can, again, be created using artisan. On the console from the root of your project, run php artisan make:controller InviteController.

Open up app/Http/Controllers/InviteController.php and define the following methods:

public function invite()
{
// show the user a form with an email field to invite a new user
}
 
public function process()
{
// process the form submission and send the invite by email
}
 
public function accept($token)
{
// here we'll look up the user by the token sent provided in the URL
}

Great, everything is set up. We can now flesh out these methods and make our invitation system come to life.

Business Logic

Here, we will work through each of the methods stubbed out above.

invite()

This is nice and simple. We need to return a view which presents a form to the user where they can enter the email address of the invitee.

The method will look something like this:

public function invite()
{
return view('invite');
}

Create the file resources/views/invite.blade.php. This view will need to contain a form that posts to /invite with an input called email:

// make use of the named route so that if the URL ever changes,
// the form will not break #winning
<form action="{{ route('invite') }}" method="post">
{{ csrf_field() }}
<input type="email" name="email" />
<button type="submit">Send invite</button>
</form>

process()

This is where the bulk of our work will be carried out.

As part of this method, we need to notify the new user that someone has sent them an invitation. To do that, let’s make use of Laravel’s mailables.

To start, we need to create a mailable class. On the console from the root of your project, run php artisan make:mail InviteCreated.

This will generate a new class called, you guessed it, InviteCreated in your app/Mail directory. Open up this class and update the constructor to accept an invite model and assign this as a public property.

use App\Invite;
 
public function __construct(Invite $invite)
{
$this->invite = $invite;
}

Now, to send the email, define a build method. This will determine who to send the email from and which view to use to generate the email.

public function build()
{
return $this->from('you@example.com')
->view('emails.invite');
}

Next, we need to generate said view file. Create the file resources/views/emails/invite.blade.php. We’ll keep this super simple:

<p>Hi,</p>
 
<p>Someone has invited you to access their account.</p>
 
<a href="{{ route('accept', $invite->token) }}">Click here</a> to activate!

“How do we have access to the $invite variable in our view,” I hear you cry! Laravel will automatically make all public properties of your mailable class available to your views.

Now, back to our InviteController, we will need to generate a unique random token which can be used to identify the new user when they accept the invitation. We will store this record in the invites table along with the email address provided by the person carrying out the invite.

use App\Invite;
use App\Mail\InviteCreated;
use Illuminate\Support\Facades\Mail;
 
...
 
public function process(Request $request)
{
// validate the incoming request data
 
do {
//generate a random string using Laravel's str_random helper
$token = str_random();
} //check if the token already exists and if it does, try again
while (Invite::where('token', $token)->first());
 
//create a new invite record
$invite = Invite::create([
'email' => $request->get('email'),
'token' => $token
]);
 
// send the email
Mail::to($request->get('email'))->send(new InviteCreated($invite));
 
// redirect back where we came from
return redirect()
->back();
}

Nice work! That’s our new invite stored, and the new user notified.

accept()

Finally, we need to allow our new users to accept the invite. This is what will happen when the user clicks the activation email we sent above.

Usually, you would probably want to capture a password and any other user details you may need at this point, but to keep this simple, we’re just going to check for the existence of the token and create the user accordingly.

Remember, the token in the URL will be passed to us as a parameter from Laravel.

use App\User;
use App\Invite;
use App\Mail\InviteCreated;
use Illuminate\Support\Facades\Mail;
 
...
 
public function accept($token)
{
// Look up the invite
if (!$invite = Invite::where('token', $token)->first()) {
//if the invite doesn't exist do something more graceful than this
abort(404);
}
 
// create the user with the details from the invite
User::create(['email' => $invite->email]);
 
// delete the invite so it can't be used again
$invite->delete();
 
// here you would probably log the user in and show them the dashboard, but we'll just prove it worked
 
return 'Good job! Invite accepted!';
}

Give It a Go!

Hit the invite URL in your browser (e.g. http://example.com/invite), enter the email address of the person you are inviting and submit the form.

Take a look in the invites table of your database; you should see new record has been created with a new unique token. Now check your email; you should have received a message containing a link to activate the new user which contains the token stored in the database.

Finally, click the link and you will be greeted with “Good job! Invite accepted!” which is a good sign. To check everything worked as expected, the invite record should no longer be in the database, but instead, a new user record should have appeared in the users table.

That’s a Wrap

Nice work! You have successfully implemented a user invitation system.

Although this is a simple example, it provides a good base to build from.

It would be trivial to extend this example to capture new user details at the point they accept the invitation as well as allowing invites to be revoked and/or re-sent.

Additionally, you could modify the code to support multitenancy or team/user relationships—though this would be somewhat more complex.

Joe Dixon photo

Founder and CTO of ubisend. Proud Father to two tiny heroes, Husband, developer, occasional globetrotter.

Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

image
Bacancy

Outsource a dedicated Laravel developer for $2,500/month. With over a decade of experience in Laravel development, we deliver fast, high-quality, and cost-effective solutions at affordable rates.

Visit Bacancy
Curotec logo

Curotec

World class Laravel experts with GenAI dev skills. LATAM-based, embedded engineers that ship fast, communicate clearly, and elevate your product. No bloat, no BS.

Curotec
Bacancy logo

Bacancy

Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $2500/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Bacancy
Laravel Forge logo

Laravel Forge

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Forge
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
NativePHP logo

NativePHP

Build rich mobile apps across iOS and Android from a single Laravel codebase. This changes everything!

NativePHP
Cut PHP Code Review Time & Bugs into Half with CodeRabbit logo

Cut PHP Code Review Time & Bugs into Half with CodeRabbit

CodeRabbit is an AI-powered code review tool that specializes in PHP and Laravel, running PHPStan and offering automated PR analysis, security checks, and custom review features while remaining free for open-source projects.

Cut PHP Code Review Time & Bugs into Half with CodeRabbit
Join the Mastering Laravel community logo

Join the Mastering Laravel community

Connect with experienced developers in a friendly, noise-free environment. Get insights, share ideas, and find support for your coding challenges. Join us today and elevate your Laravel skills!

Join the Mastering Laravel community
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
Lucky Media logo

Lucky Media

Get Lucky Now - the ideal choice for Laravel Development, with over a decade of experience!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel E-Commerce

E-Commerce for Laravel. An open-source package that brings the power of modern headless e-commerce functionality to Laravel.

Lunar: Laravel E-Commerce
LaraJobs logo

LaraJobs

The official Laravel job board

LaraJobs
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS Starter Kit

SaaSykit is a Multi-tenant Laravel SaaS Starter Kit that comes with all features required to run a modern SaaS. Payments, Beautiful Checkout, Admin Panel, User dashboard, Auth, Ready Components, Stats, Blog, Docs and more.

SaaSykit: Laravel SaaS Starter Kit

The latest

View all →
Laravel Nightwatch - Deep monitoring & insights, no matter where you deploy. image

Laravel Nightwatch - Deep monitoring & insights, no matter where you deploy.

Read article
Filament v4 Beta - Feature Overview image

Filament v4 Beta - Feature Overview

Read article
AnyCable Laravel Broadcaster image

AnyCable Laravel Broadcaster

Read article
Parse Localized Numbers with Laravel's Number Class image

Parse Localized Numbers with Laravel's Number Class

Read article
Manage Taxonomies, Categories, and Tags in Laravel image

Manage Taxonomies, Categories, and Tags in Laravel

Read article
Extract Arrays from Any Data Type with Laravel's Arr::from Method image

Extract Arrays from Any Data Type with Laravel's Arr::from Method

Read article