Laravel 5.3 Auth CAPTCHA Example

Laravel Auth CAPTCHA Example demonstrates how to integrate Laravel CAPTCHA Package into login, register and reset password forms in a scenario where Laravel Auth is used to authenticate users to your application.

First Time Here?

Check the BotDetect Laravel 5.3 Captcha Quickstart for key integration steps.

Alongside the Captcha image, the user is provided with an input field to retype the displayed characters. Depending on if the Captcha code entered matches the displayed one or not, a message stating the validation result is shown on the form.

The simple code showing the message in this example would of course be replaced with useful form processing code in a real world scenario.

The default in Laravel 5.3 ships an example to authenticate users that is used Laravel Auth, but no captcha image is created. Here's what we started:

First, we need to configure database connection with entering connection details into the config/database.php file.

Next, we need to create users and password_resets tables -- using Migrations.

To create that tables, run the following command in your application's root directory:

Files for this ('bd-captcha-laravel-5.3-examples') example are:

The files are available for download as a part of the BotDetect Captcha Laravel integration package.

Routing – /routes/web.php

Route::auth();

In the code above we have registered the typical authentication routes for our application.

Config – /config/botdetect.xml

<?xml version="1.0" encoding="UTF-8"?>
<botdetect xmlns="https://captcha.com/schema/php"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://captcha.com/schema/php
     https://captcha.com/schema/php/botdetect-4.2.3.xsd">

  <captchaStyles>
    <captchaStyle>
      <name>LoginCaptcha</name>
      <userInputID>CaptchaCode</userInputID>
      <codeLength>4-6</codeLength>
    </captchaStyle>
    
    <captchaStyle>
      <name>RegisterCaptcha</name>
      <userInputID>CaptchaCode</userInputID>
      <codeLength>4-7</codeLength>
      <codeStyle>Alpha</codeStyle>
    </captchaStyle>
    
    <captchaStyle>
      <name>ResetPasswordCaptcha</name>
      <userInputID>CaptchaCode</userInputID>
      <codeLength>3-6</codeLength>
      <customLightColor>#9966FF</customLightColor>
    </captchaStyle>
    
  </captchaStyles>

</botdetect>

In order to use the Laravel CAPTCHA Package, we have declared Captcha configuration which will be used when showing Captcha image in login, register, and reset password views. Detailed description of this approach is available in a BotDetect Laravel 5.3 integration guide.

View – /resources/views/layouts/app.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>Laravel</title>

  [...]

</head>

  [...]

The above code is defining a Blade Layout.

View – /resources/views/auth/login.blade.php

@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">Login</div>
        <div class="panel-body">
          <form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
            {!! csrf_field() !!}

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

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

                @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 class="col-md-4 control-label">Password</label>

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

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

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

              <div class="col-md-6">
                {!! simple_captcha_image_html('LoginCaptcha') !!}
                <input type="text" class="form-control" name="CaptchaCode" id="CaptchaCode">

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

            <div class="form-group">
              <div class="col-md-6 col-md-offset-4">
                <div class="checkbox">
                  <label>
                    <input type="checkbox" name="remember"> Remember Me
                  </label>
                </div>
              </div>
            </div>

            <div class="form-group">
              <div class="col-md-6 col-md-offset-4">
                <button type="submit" class="btn btn-primary">
                  <i class="fa fa-btn fa-sign-in"></i>Login
                </button>

                <a class="btn btn-link" href="{{ url('/password/reset') }}">Forgot Your Password?</a>
              </div>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
@endsection

The above code is to display authentication in a view, we show Captcha image by calling simple_captcha_image_html() helper function. It is required to pass a captcha style name defined in config/botdetect.xml file (i.e. LoginCaptcha). We have also added Captcha Code input field to view.

View – /resources/views/auth/register.blade.php

@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>
        <div class="panel-body">
          <form class="form-horizontal" role="form" method="POST" action="{{ url('/register') }}">
            {!! csrf_field() !!}

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

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

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

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

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

                @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 class="col-md-4 control-label">Password</label>

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

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

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

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

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

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

              <div class="col-md-6">
                {!! simple_captcha_image_html('RegisterCaptcha') !!}
                <input type="text" class="form-control" name="CaptchaCode" id="CaptchaCode">

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

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

The above code is to display authentication in a view, we show Captcha image by calling simple_captcha_image_html() helper function. It is required to pass a captcha style name defined in config/botdetect.xml file (i.e. RegisterCaptcha). We have also added Captcha Code input field to view.

View – /resources/views/auth/passwords/email.blade.php

@extends('layouts.app')

<!-- Main Content -->
@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">Reset Password</div>
        <div class="panel-body">
          @if (session('status'))
            <div class="alert alert-success">
              {{ session('status') }}
            </div>
          @endif

          <form class="form-horizontal" role="form" method="POST" action="{{ url('/password/email') }}">
            {!! csrf_field() !!}

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

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

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

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

              <div class="col-md-6">
                {!! simple_captcha_image_html('ResetPasswordCaptcha') !!}
                <input type="text" class="form-control" name="CaptchaCode" id="CaptchaCode">

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

            <div class="form-group">
              <div class="col-md-6 col-md-offset-4">
                <button type="submit" class="btn btn-primary">
                  <i class="fa fa-btn fa-envelope"></i>Send Password Reset Link
                </button>
              </div>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
@endsection

The above code is to display authentication in a view, we show Captcha image by calling simple_captcha_image_html() helper function. It is required to pass a captcha style name defined in config/botdetect.xml file (i.e. ResetPasswordCaptcha). We have also added Captcha Code input field to view.

Controller – /app/Http/Controllers/Auth/LoginController.php

<?php

namespace App\Http\Controllers\Auth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
  /*
  |--------------------------------------------------------------------------
  | Login Controller
  |--------------------------------------------------------------------------
  |
  | This controller handles authenticating users for the application and
  | redirecting them to your home screen. The controller uses a trait
  | to conveniently provide its functionality to your applications.
  |
  */

  use AuthenticatesUsers;

  /**
   * Where to redirect users after login.
   *
   * @var string
   */
  protected $redirectTo = '/home';

  /**
   * Create a new controller instance.
   *
   * @return void
   */
  public function __construct()
  {
    $this->middleware('guest')->except('logout');
  }

  /**
   * Validate the user login request.
   *
   * @param  \Illuminate\Http\Request  $request
   * @return void
   */
  protected function validateLogin(Request $request)
  {
    $this->validate($request, [
      $this->username() => 'required|string',
      'password' => 'required|string',
      'CaptchaCode' => 'required|valid_simple_captcha',
    ]);
  }
}

The Controller part of the example provides necessary helpers and data used by View, and adds the Captcha validation functionality as outlined in the BotDetect Laravel 5.3 integration guide.

To add Captcha validation on Login form submit, we need to override the validateLogin method of AuthenticatesUsers trait and then use the valid_simple_captcha validation rule for Captcha code input.

Controller – /app/Http/Controllers/Auth/RegisterController.php

<?php

namespace App\Http\Controllers\Auth;

use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;

class RegisterController extends Controller
{
  /*
  |--------------------------------------------------------------------------
  | Register Controller
  |--------------------------------------------------------------------------
  |
  | This controller handles the registration of new users as well as their
  | validation and creation. By default this controller uses a trait to
  | provide this functionality without requiring any additional code.
  |
  */

  use RegistersUsers;

  /**
   * Where to redirect users after registration.
   *
   * @var string
   */
  protected $redirectTo = '/home';

  /**
   * Create a new controller instance.
   *
   * @return void
   */
  public function __construct()
  {
    $this->middleware('guest');
  }

  /**
   * Get a validator for an incoming registration request.
   *
   * @param  array  $data
   * @return \Illuminate\Contracts\Validation\Validator
   */
  protected function validator(array $data)
  {
    return Validator::make($data, [
      'name' => 'required|string|max:255',
      'email' => 'required|string|email|max:255|unique:users',
      'password' => 'required|string|min:6|confirmed',
      'CaptchaCode' => 'required|valid_simple_captcha',
    ]);
  }

  /**
   * Create a new user instance after a valid registration.
   *
   * @param  array  $data
   * @return \App\User
   */
  protected function create(array $data)
  {
    return User::create([
      'name' => $data['name'],
      'email' => $data['email'],
      'password' => Hash::make($data['password']),
    ]);
  }
}

The Controller part of the example provides necessary helpers and data used by View, and adds the Captcha validation functionality as outlined in the BotDetect Laravel 5.3 integration guide.

On HTTP POST request (user submit), we validate the user's Captcha code input in the validator() method by using the valid_simple_captcha validation rule that will be called in the register() of RegistersUsers trait.

Controller – /app/Http/Controllers/Auth/ForgotPasswordController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;

class ForgotPasswordController extends Controller
{
  /*
  |--------------------------------------------------------------------------
  | Password Reset Controller
  |--------------------------------------------------------------------------
  |
  | This controller is responsible for handling password reset emails and
  | includes a trait which assists in sending these notifications from
  | your application to your users. Feel free to explore this trait.
  |
  */

  use SendsPasswordResetEmails;

  /**
   * Create a new controller instance.
   *
   * @return void
   */
  public function __construct()
  {
    $this->middleware('guest');
  }

  /**
   * Validate the email for the given request.
   *
   * @param  \Illuminate\Http\Request  $request
   * @return void
   */
  protected function validateEmail(Request $request)
  {
    $this->validate($request, [
      'email' => 'required|email',
      'CaptchaCode' => 'required|valid_simple_captcha',
    ]);
  }
}

The Controller part of the example provides necessary helpers and data used by View, and adds the Captcha validation functionality as outlined in the BotDetect Laravel 5.3 integration guide.

To add Captcha validation on reset passworld form submit, we need to override the validateEmail method of SendsPasswordResetEmails trait and then use the valid_simple_captcha validation rule for Captcha code input.