Surfe.be - passive income

Laravel 5.6 :Customizing the default Auth : Activate account after email verification using Laravel Notification

Activate account after email verification

Many web applications require users to verify their email addresses before using the application. Rather than forcing you to re-implement this on each application, Laravel provides convenient methods for sending and verifying email verification requests. But here i am going to customize this basic default auth mechanism . Laravel provides the Basic Authentication out of the box which includes the basic login, registration, and password reset functionalities. These functionalities can be easily customized. This is the beauty of Laravel framework. In this tutorial we are going to customize the basic registration functionality of the Laravel and acount activation functionality after user registration.

email-verification-in-laravel

Email Verification and Why It’s Important

Before sending any other email to the address you collected you should always verify that the owner of the email address is the same entity who provided it to you. This is not only helpful to the registrant (as in the "forgot password" scenario described in another answer) and collector (improving the quality of the collection) but also the owner of the email address (especially if this is not the same person as the registrant).

As someone who has a simple, short gmail email address I get 10 to 20 unsolicited "Thanks (someone else's name) for signing up for our program!" emails each year that are sent from legitimate/non-spam organizations. It doesn't sound like a big deal, but often it takes about 30 minutes of effort to correct this (typically because of having to make a phone call and explain the situation two or three times to different people). Thankfully I believe this usually happens as the result of an honest mistake. However, what if someone thought it'd be funny to sign me up for a bunch of email lists that I'd surely not want? If the senders don't verify the address first then I'd have a lot of unsubscribing to do later 🤣

So, let’s get started with a fresh installation of Laravel.

composer create-project --prefer-dist laravel/laravel auth

Let’s make some changes on the users table’s migration: Go to your migration folder and open users table and paste this following code in your users table schema.

 Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('username')->unique();
            $table->string('password');
            $table->string('activation_code')->nullable();
            $table->boolean('status')->default(0);
            $table->rememberToken();
            $table->timestamps();
        });

Next we need to generate the Auth Scaffolding provided by Laravel, using the following command on our terminal:

php artisan make:auth

We are interested in customizing the Registration system. So we will be updating the RegisterController.php. We are implementing Laravel Notifications so let’s create a new notification using the following command on the terminal:

php artisan make:notification UserRegisteredSuccessfully

This command generates a new notification class for us, inside the directory ‘App/Notifications’. Let’s edit the UserRegisteredSuccessfully.php

namespace App\Notifications;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class UserRegisteredSuccessfully extends Notification
{
    use Queueable; protected $user;
  
    public function __construct(User $user)
    {
        $this->user = $user;
    }
  
    public function via($notifiable)
    {
        return ['mail'];
    }
   
    public function toMail($notifiable)
    {
        /** @var User $user */
        $user = $this->user;
        return (new MailMessage)
            ->from(env('ADMIN_MAIL'))
            ->subject('Successfully created new account')
            ->greeting(sprintf('Hello %s', $user->name))
            ->line('You have successfully registered to our system. Please activate your account.')
            ->action('Click Here', route('activate.user', $user->activation_code))
            ->line('Thank you for using our application!');
    }
  
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
}

We need to define, a new route for validating / activating the account with named route ‘activate.user’ which is used in the Notification class (line no 55 above).

In our routes/web.php:

$this->get('/verify-user/{code}', 'Auth\RegisterController@activateUser')->name('activate.user');

Now, let’s edit our RegisterController , we will add activateUser method and also make changes in the user registration.

namespace App\Http\Controllers\Auth;
use App\Notifications\UserRegisteredSuccessfully;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
class RegisterController extends Controller
{
    use RegistersUsers;
  
    protected $redirectTo = '/home';
   
    public function __construct()
    {
        $this->middleware('guest');
    }
  
    protected function register(Request $request)
    {
        /** @var User $user */
        $validatedData = $request->validate([
            'name'     => 'required|string|max:255',
            'email'    => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:6|confirmed',
        ]);
        try {
            $validatedData['password']        = bcrypt(array_get($validatedData, 'password'));
            $validatedData['activation_code'] = str_random(30).time();
            $user                             = app(User::class)->create($validatedData);
        } catch (\Exception $exception) {
            logger()->error($exception);
            return redirect()->back()->with('message', 'Unable to create new user.');
        }
        $user->notify(new UserRegisteredSuccessfully($user));
        return redirect()->back()->with('message', 'Successfully created a new account. Please check your email and activate your account.');
    }
   
    public function activateUser(string $activationCode)
    {
        try {
            $user = app(User::class)->where('activation_code', $activationCode)->first();
            if (!$user) {
                return "The code does not exist for any user in our system.";
            }
            $user->status          = 1;
            $user->activation_code = null;
            $user->save();
            auth()->login($user);
        } catch (\Exception $exception) {
            logger()->error($exception);
            return "Whoops! something went wrong.";
        }
        return redirect()->to('/home');
    }
}

Here we are overriding the ‘register’ method of RegistersUser trait. After the user is registered we call the notify method and pass new instance of our UserRegisteredSuccessfully notification class which sends the notification mail to individual user with a link to activate the account.

Now, we need to update the fillable fields in our ‘User’ model.

protected $fillable = [
    'name', 'email', 'username', 'password' , 'status', 'activation_code',
];

Also, we need to update our mail settings, for the testing purpose we can use Mailtrap.io. So we need to update the following keys in our .env file:

MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_user_name
MAIL_PASSWORD=your_mail_password

Let’s edit our register.blade.php file to: add new username field and display the error message:

@extends('layouts.app')

@section('content')
  <div class="container">
    <div class="row">
      <div class="col-md-8 col-md-offset-2">
        <div class="panel panel-default">
          <div class="panel-heading">Register</div>
          @if(session()->has('message'))
            <div class="alert alert-success">
              {{ session()->get('message') }}
            </div>
          @endif

          <div class="panel-body">
            <form class="form-horizontal" method="POST" action="{{ route('register') }}">
              {{ csrf_field() }}

              <div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
                <label for="name" class="col-md-4 control-label">Name</label>

                <div class="col-md-6">
                  <input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}" required
                         autofocus>

                  @if ($errors->has('name'))
                    <span class="help-block">
                                        <strong>{{ $errors->first('name') }}</strong>
                                    </span>
                  @endif
                </div>
              </div>

              <div class="form-group{{ $errors->has('username') ? ' has-error' : '' }}">
                <label for="name" class="col-md-4 control-label">Username</label>

                <div class="col-md-6">
                  <input id="name" type="text" class="form-control" name="username" value="{{ old('username') }}" required
                         autofocus>

                  @if ($errors->has('username'))
                    <span class="help-block">
                                        <strong>{{ $errors->first('username') }}</strong>
                                    </span>
                  @endif
                </div>
              </div>

              <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                <label for="email" class="col-md-4 control-label">E-Mail Address</label>

                <div class="col-md-6">
                  <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required>

                  @if ($errors->has('email'))
                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                  @endif
                </div>
              </div>

              <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                <label for="password" class="col-md-4 control-label">Password</label>

                <div class="col-md-6">
                  <input id="password" type="password" class="form-control" name="password" required>

                  @if ($errors->has('password'))
                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                  @endif
                </div>
              </div>

              <div class="form-group">
                <label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>

                <div class="col-md-6">
                  <input id="password-confirm" type="password" class="form-control" name="password_confirmation"
                         required>
                </div>
              </div>

              <div class="form-group">
                <div class="col-md-6 col-md-offset-4">
                  <button type="submit" class="btn btn-primary">
                    Register
                  </button>
                </div>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
@endsection

Let’s serve our application and then try to register a new user. This sends a new mail to the user. User can easily activate their account by clicking on the button. If you like this tutorial don’t forget to share and if you find any bugs please leave a comment.

Leave a comments

LET'S SOCIALITE

Recent Tweets

RECOMMENDED POST