Laravel 5 is a big change over the previous version. It is even more opinionated and makes heavy use of modern PHP language features.

It also includes, like previous versions, the scaffolding for user authentication and management. This includes user account creation and password reseting. It does not include email activation of new user accounts.

I searched for ready-made email activation solutions, but I struggled to find decent ones. I did find the following two blog posts:

  1. Email activation with Laravel by Luca Bernardino
  2. Email Verification With Laravel by Ben Smith

These posts got me started, but they’re either too outdated (not specifically for Laravel 5) or make the error of modifying core files. And the one that specifically uses Laravel 5 was not doing this in a very Laravel 5 way.

The Laravel 5 Way

The answer I found was to use Middleware.

You see, I really didn’t want to recreate the built in user authentication and password reset functionality. That code is really well integrated and works well.

I realised that I could enforce an email activation flow between authenticating a user and using any controller that needs an authenticated user by using my own middleware layer.

My Middleware

I created my middleware as per the instructions in the Laravel documentation and set it up to do the following for my controllers that require an authenticated and activated user:

Authenticate user
    Is the user's "confirmed" flag set to false?
        Yes
            Is the user's "confirmed_token" set?
                No
                    Generate token and set in user's object and save
                    Email token to user as part of activation email
            Redirect to Activate Account view
    Carry on

I added my middleware to any controllers that require activated users. Simply adding to the controller’s middleware.

public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('activated');
    }

This will cause my middleware to be executed after the user has logged in and before the controller begins processing the requested method.

Here is my middleware that is saved as app/Http/Middleware/UserConfirmed.php:

<?php namespace App\Http\Middleware;

    use Closure;
    use Illuminate\Contracts\Auth\Guard;

    class UserConfirmed {

        /**
         * The Guard implementation.
         *
         * @var Guard
         */
        protected $auth;

        /**
         * Create a new filter instance.
         *
         * @param  Guard  $auth
         * @return void
         */
        public function __construct(Guard $auth)
        {
            $this->auth = $auth;
        }

        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next)
        {
            $user = $this->auth->getUser();
            $confirmed = $user->confirmed;

            if (isset($confirmed) && $confirmed == "0")
            {
                // If the user has not had an activation token set
                $confirmation_code = $user->confirmation_code;

                if (empty($confirmation_code))
                {
                    // generate a confirmation code
                    $key = \Config::get('app.key');
                    $confirmation_code = hash_hmac('sha256', str_random(40), $key);
                    $user->confirmation_code = $confirmation_code;
                    $user->save();
                    \Mail::send('emails.activate', ['token' => $confirmation_code, 'name' => $user->name], function($message) use ($user){
                        $message->to($user->getEmailForPasswordReset(), $user->name)
                                ->subject('Activate your Notify account');
                    });
                }
                return redirect()->guest('/activate');
            }
            return $next($request);
        }
    }

If you look carefully, you’ll see that I use the authenticated user’s object to get and set the users tables new “confirmed” and “confirmation_code” fields.

End Result

This approach is great! No extra database queries unless the user has not received an activation token yet and the activation page is only accessible if the user is already authenticated.

I will add the ability for a user to send themselves a new token or to manually enter a token into the activation page instead of allowing a user to click a link in the email.

Problems

I must still resolve the process flow if an unauthenticated user tries to activate their account.

This is definitively the Laravel Way to include email-based user activation.