How to Implement Email Verification on Laravel 5 1
So I struggle with this for a day or two. First I build the authentication system from scratch and created a new method to generate and verify the email token, worked pretty well. But why not using the authentication system which comes out of the box with Laravel 5? If you are using 5.1 you get the login throttling for free as well! So reason enough to rewrite the code and implement the email verification with the build in authentication system. Let’s go.
Just a quick note; I assume you already have a Laravel 5.x app up & running, I’m not covering the setup of a new app in this post.
What are we building?
To prevent spam and fake account on your application you may want to verify their e-mail they sign up with. In order to do this we’re sending them an e-mail after they signup with a confirmation link. When they click on the link, we will do a simple lookup to see if the token matches with an e-mail address in our database. If there’s a match, we will activate their account, otherwise we will do nothing and the newly registered user will not be able to login.
Preparing the database
Think about it, how do we want to verify an user’s e-mail address? There are hundreds of ways to implement this, but for this short tutorial we’ll go with a very basic verification process. We will generate a unique token and store this in the database with the user that signup. After they verified their e-mail address we will activate their account, so we will add a ‘token’ and ‘confirmed’ column to the database.
1php artisan make:migration add_token_and_confirmed_column_to_users_table
1// add_token_and_confirmed_column_to_users_table.php
2
3public function up()
4{
5Schema::table('users', function ($table) {
6 $table->string('token');
7 $table->boolean('confirmed')->default(false);
8 });
9}
10
11public function down()
12{
13Schema::table('users', function ($table) {
14 $table->dropColumn('token');
15 $table->dropColumn('confirmed');
16 });
17}
1php artisan migrate
Great now we have our database prepared. Let’s continue and create the token.
1//User.php
2
3public static function boot()
4{
5parent::boot();
6
7static::creating(function($user) {
8$user->token = str_random(30);
9});
10}
Now we have a static method which is called when a new user will be created. We hook into the creating method, just before the data is persisted to the database. Go ahead, create a new user. The user should now have a token stored in the database, great!
Now we need to send an e-mail to the user to verify their e-mail address. Let’s go and create an sendEmailConfirmationTo method. Since we’re firing off an email, I would like to store this method in a Mailer class. Let’s create a new Mailer class.
1//AppMailer.php
2
3<?php
4
5namespace App\Mailers;
6
7use App\User; // Do not forget to import this!
8use Illuminate\Contracts\Mail\Mailer;
9
10class AppMailer {
11
12 protected $mailer;
13
14 protected $from = 'admin@example.com'; // Who's sending this email?
15
16 protected $to;
17
18 protected $view; // Used to passthrough our email template
19
20 protected $data = [];
21
22 public function __construct(Mailer $mailer)
23 {
24 $this->mailer = $mailer;
25 }
26
27 public function sendEmailConfirmationTo(User $user)
28 {
29 $this->to = $user->email;
30 $this->view = 'emails.confirm'; // The view used stored at resources/views/email/confirm.blade.php
31 $this->data = compact('user'); // Passing though the user object to access the token and if you want their name.
32
33 $this->deliver();
34 }
35
36 public function deliver()
37 {
38 $this->mailer->send($this->view, $this->data, function($message) {
39 $message->from($this->from, 'Administrator')
40 ->to($this->to);
41 });
42 }
43
44}
1// resources/views/email/confirm.blade.php
2<!DOCTYPE html>
3<html>
4<head>
5 <title>Thanks for signing up!</title>
6</head>
7<body>
8 Thanks for signing up!
9 Please<? {{ ("{token}") }}'>confirm your email address.
10</body>
11</html>
Now we have our token stored to the database and we have our mailer setup to send an email with the token to the user. Now we have to register the route to confirm our email address.
1// routes.php
2
3Route::get('auth/register', 'Auth\AuthController@getRegister');
4Route::post('auth/register', 'Auth\AuthController@postRegister');
5Route::get('auth/confirm/{email_token}', 'Auth\AuthController@confirmEmail');
As you see when the user visit the link with the token we call the confirmEmail method on the AuthController, let’s create this.
Eh? wait! the AutController.php has no logic in it! Where’s everything go to? Well Laravel uses traits to import this logic. Let’s digg in and go to the
AuthenticatesAndRegistersUsers trait. As you can see this trait is using two other traits, AuthenticatesUsers and RegistersUsers trait.
1<?php
2
3namespace Illuminate\Foundation\Auth;
4
5trait AuthenticatesAndRegistersUsers
6{
7use AuthenticatesUsers, RegistersUsers {
8AuthenticatesUsers::redirectPath insteadof RegistersUsers;
9}
10}
Since we store the token when a new user signup, we need to extend the RegistersUsers trait. Let’s dig a bit further and go to the RegistersUsers trait.
There we go, as you can see all the logic for creating a new user is stored in this trait. Let’s call our sendEmailConfirmationTo method after a user has signed up.
1public function postRegister(Request $request, AppMailer $mailer)
2{
3$validator = $this->validator($request->all());
4
5if ($validator->fails()) {
6$this->throwValidationException(
7$request, $validator
8);
9}
10
11$user = User::create($request->all());
12$mailer->sendEmailConfirmationTo($user);
13
14flash('Please confirm your emailaddress');
15
16return redirect($this->redirectPath());
17}
As you can see, first we validate the request, if validation fails we throw an exception and show the errors to the users. If we succeed, we will create a new user with the request and tell them to confirm their email address. Great now we have send a new email to the user after they signed up. Now we have to confirm their email address. Remember the confirmEmail method we call when the user visit the link to verify their email? Let’s create this.
1public function confirmEmail($token)
2{
3
4User::where('token', $token)->firstOrFail()->confirmEmail();
5
6return redirect('login')->with('message', 'You are now confirmed, Please login.');
7}
So when the user clicks on the link, we accept the token, do a lookup on the users table to see if the token matches with one of the tokens stored and call the confirmEmail method on the user model.
Go back to the User.php file and let’s add this method.
1public function confirmEmail()
2{
3$this->confirmed = true;
4$this->token = null;
5$this->save();
6}
So now we set the confirmed to true, we remove the token since we don’t need this anymore and we store it in the database.
Well that’s it. Of course we have tons of improvements but this should get you started with email verification.